2012-07-04 5 views
7

Eventuali duplicati:
Calling class method through NULL class pointerPerché il metodo di chiamata tramite puntatore nullo "funziona" in C++?

#include <iostream> 
using namespace std; 
class test 
{ 
    int i; 
public: 
    test():i(0){ cout << "ctor called" << endl;} 
    void show() 
    { 
     cout<<"show fun called"<<endl; 
    } 
}; 

int main(int argc , char *argv[]) 
{ 
    test *ptr = NULL; 
    ptr->show(); 
    return 0; 
} 

chiaramente, non ctor sarà chiamato. È questo standard? o solo qualche ottimizzazione del compilatore in quanto questo puntatore non è usato nella funzione membro show()?

+5

Il dereferenziamento di un puntatore nullo è UB. – chris

+2

Aggiungi 'i = 1;' all'interno di 'show()' e prova ad eseguirlo. –

+1

chris, UB significa implementazione del compilatore? e sto usando g ++ 4.6.3. Jesse Bene, certo, seg colpa, non c'è dubbio. Mi chiedo se il compilatore genererà il codice senza questo per la funzione membro che non ne ha bisogno. – bbc

risposta

22

Il puntatore non è necessario per chiamare il metodo. Il tipo di puntatore è noto, quindi il codice per il metodo è noto. Il metodo non utilizza this, quindi esegue il codice bene. È un comportamento non definito, ma è più efficiente non controllare se il puntatore è NULL, quindi viene eseguito.

+0

(Come) un metodo virtuale influenzerebbe il suo comportamento osservato? –

+2

Mi aspetto che una chiamata al metodo virtuale fallisca, poiché è necessario cercare il metodo nel vtable, che troverà dall'altra parte del puntatore, ma il puntatore è NULL. –

+0

errore seg per virtual con g ++, non sicuro che questo dipenda anche dall'implementazione. il compilatore genererà vptr e vtblr senza oggetto di classe? Immagino non per ragioni di efficienza? – bbc

1

Non è valido, il comportamento non è definito e i risultati effettivi dipendono dal compilatore.

+0

Bene, è valido. __qualsiasi funzione che non accede a questo puntatore è solo una funzione statica. Basta aggiungere "statico" - è il meglio che puoi fare nel codice che è statico per definizione :) E obbliga la funzione a usare __cdecl, quindi non c'è questo puntatore. Si noti che l'aggiunta di virtual renderà quindi la preparazione più complicata che richiede il dereferenziamento del puntatore e quindi segfault. –

-1

Bene, innanzitutto, non è valido in quanto richiama un comportamento non definito. Stai davvero chiedendo perché il compilatore lo permette, e la risposta è perché questo è un codice con la testa di ossa che semplicemente non si presenterà in un'applicazione reale, quindi perché preoccuparsi? Il vero problema si presenta quando il puntatore viene reso non valido in fase di esecuzione in un modo che non può essere anticipato dall'analisi del codice statico.

Il compilatore non è lì per tenere la mano, è lì per compilare il codice in base allo standard. Se offre avvisi utili quindi grandi, ma non c'è nulla di sintatticamente o semanticamente illegale lì, stai semplicemente scrivendo un codice che causa un comportamento indefinito.

+0

grazie per il consiglio. – bbc

8

Se si guarda l'assieme (per almeno un compilatore), è possibile vedere perché viene eseguito (anche se è un comportamento indefinito come molti hanno sottolineato). Per queste due linee:

test *ptr = NULL; 
ptr->show(); 

Questo assemblaggio è generato (in un compilatore Ho appena provato):

00000004: C7 45 FC 00 00 00 mov   dword ptr [ebp-4],0 
      00 
0000000B: 8B 4D FC   mov   ecx,dword ptr [ebp-4] 
0000000E: E8 00 00 00 00  call  [email protected]@@QAEXXZ 

spinge il NULL (0) nello stack e richiama il metodo dato che l'indirizzo di il metodo è indipendente dall'istanza dell'oggetto reale.

Problemi correlati