2013-05-09 14 views
5

Consideriamo un banco di prova piccola unitàrisoluzione del riferimento e ritorno con riferimento

struct A 
{ 
    virtual void func(){} 
    A& foo() 
    { 
    A *obj = reinterpret_cast<A*>(0xdeadbeef); 
    return *obj; //1 
    } 
}; 

int main() 
{ 
    A obj = obj.foo(); 
} 

Adiacente 1 è vero implementazione definita/non specificato che la deferenza non sarebbe accaduto, come stiamo tornando per riferimento e il programma non potrebbe andare in crash se un l'accesso esplicito all'oggetto puntato non è fatto?

ho avuto discussione con uno dei miei colleghi in cui ha ricordato che il compilatore, nella maggior parte dei casi, sarebbe ottimizzare la risoluzione del riferimento di obj come stiamo tornando per riferimento e questo codice non potrebbe andare in crash?

Grazie

+0

La mia comprensione è: il compilatore non è obbligato a 1) eseguire codice che non accada nulla 2) eseguire codice che produce un comportamento indefinito: http://blog.llvm.org/2011/05/what-every- c-programmer-should-know_14.html – Patashu

+0

Anche io credo che il comportamento non sia definito e non dovremmo fare affidamento sull'implementazione sottostante in questo caso. –

+2

È un comportamento indefinito e non dovresti mai fare affidamento su comportamenti indefiniti facendo ciò che pensi che farà, sì. Ma non si romperà necessariamente, se il compilatore decide che è un codice morto o indefinito e non vale la pena produrre codice, parlando da una prospettiva accademica. – Patashu

risposta

4

ho smontare il codice in MS VC8.0, e trovano le cose più interessanti:

006D48D6 mov   dword ptr [ebp-8],ecx 
    A *obj = reinterpret_cast<A*>(0xdeadbeef); 
006D48D9 mov   dword ptr [obj],0DEADBEEFh 
     return *obj; //1 
006D48E0 mov   eax,dword ptr [obj] //2 
    } 
006D48E3 mov   esp,ebp 
006D48E5 pop   ebp 
006D48E6 ret  

// 2 mostra che basta mettere l'indirizzo del obj al registro EAX come valore di ritorno .

006D39FC lea   ecx,[ebp-190h] 
006D3A02 call  A::foo (6A8C12h) 
006D3A07 push  eax //3 
006D3A08 lea   ecx,[ebp-190h] 
006D3A0E call  A::A (6B89BEh) 

eax è 0xdeadbeef e premere per impilare come fa la variabile locale temporanea. Di noi chiamiamo il costruttore di copie (che è banale). Tutte queste azioni sono solo passare l'indirizzo (che è illegale ma il programma non interessa). Perché la struttura A non ha alcun membro che è associato a un oggetto specifico, e il programma non tenterà di trovare oggetto specifico tramite dereferenziazione se non lo fa t need.So questa bomba non è stata licenziata.

 A *obj = reinterpret_cast<A*>(0xdeadbeef); 
     A tmp ; 
     temp = *obj; 

Anche questo è OK perché operatore = è passare anche da riferimento che di fatto passare l'ADDRESS.If si aggiunge una variabile membro, fallirà perché sarà cercare di trovare e copiare il membro.

+2

+1 per scavare, anche se non risponde alla domanda. – qdii

Problemi correlati