2016-06-14 37 views
6

Non capisco cosa farebbe la seguente dichiarazione (specialmente la seconda riga)?Riassegna oggetto unique_ptr con istruzioni make_unique - Perdita di memoria?

auto buff = std::make_unique<int[]>(128); 
buff = std::make_unique<int[]>(512); 

disposta la seconda chiamata a make_unique seguita da operatore di assegnazione saranno deallocare memoria allocata da prima chiamata, o ci saranno perdita di memoria? Devo usare buff.reset(new int[512]);?

Ho eseguito il debug, ma non ho trovato alcun operator= chiamato, né alcun distruttore essere invocato (da unique_ptr).

+0

Scommetto che il compilatore ha semplicemente eliminato la prima chiamata. – kennytm

+0

'operator =' deve essere chiamato e l'oggetto precedentemente gestito verrà cancellato. Nessuna perdita di memoria qui. – songyuanyao

+0

La dichiarazione assegna un array di numero intero di dimensione 512. Vedere il distruttore chiamato qui userà "delete buff" per deallocare la memoria, ma è stata allocata memoria per un array di numero intero in modo ideale dovrebbe essere chiamato "delete [] buff". Per tale requisito è possibile passare un deallocatore personalizzato con la dichiarazione del puntatore intelligente. – sagar

risposta

4

gcc 5.3:

#include <memory> 

extern void emit(int*); 

int main() 
{ 
    // declare and initialise buf 
    auto buff = std::make_unique<int[]>(128); 

    // make_unique on the RHS returns a temporary 
    // - therefore an r-value reference 

    // therefore this becomes and operator=(unique_ptr&&) 
    // (move-assignment) 
    buff = std::make_unique<int[]>(512); 

    // something to get the compiler to emit code 
    emit(buff.get()); 
} 

produce il montaggio:

main: 
     pushq %r12 
     movl $512, %edi 
     pushq %rbp 
     pushq %rbx 
     call operator new[](unsigned long) ; <-- new (1) 
     movl $64, %ecx 
     movq %rax, %rbp 
     xorl %eax, %eax 
     movq %rbp, %rdi 
     rep stosq 
     movl $2048, %edi 
     call operator new[](unsigned long) ; <<-- new (2) 
     movl $2048, %edx 
     xorl %esi, %esi 
     movq %rax, %rdi 
     movq %rax, %rbx 
     call memset 
     movq %rbp, %rdi 
     call operator delete[](void*)  ;<-- delete (1) 
     movq %rbx, %rdi 
     call emit(int*) 
     movq %rbx, %rdi 
     call operator delete[](void*)  ;<-- delete (2) 
     popq %rbx 
     xorl %eax, %eax 
     popq %rbp 
     popq %r12 
     ret 
     movq %rax, %r12 
     movq %rbp, %rbx 
.L3: 
     movq %rbx, %rdi 
     vzeroupper 
     call operator delete[](void*)  ;<-- handles a failed assignment 
     movq %r12, %rdi 
     call _Unwind_Resume 
     movq %rax, %r12 
     jmp  .L3 
+1

Una spiegazione di come funzionano i puntatori intelligenti e perché non ci sono perdite sono stato più utile a parer mio di un gruppo di output di assemblaggio specifico del compilatore – gigabytes

+0

@gigabytes perdonami.Ho imparato a programmare in assembler nel 1981. Era il mio primo linguaggio per computer quindi tendo a vedere ogni altra lingua in termini di esso Ho ipotizzato che l'assemblaggio annotato sarebbe la migliore spiegazione: cosa ho lasciato poco chiaro? –

+0

Per concludere che queste due righe chiamano effettivamente 'new' e' delete' come previsto sarebbe stato sufficiente per inserire 'printf'statements in costruttori e distruttori , dopo aver verificato che il compilatore emettesse il codice come hai fatto tu, senza ricorrere ad asm.Ma a chi fa questa domanda, è più utile sapere * perché * questo è il caso, cioè che lo standard dice che "unique_ptr" si comporta in questo modo, e le ragioni per cui "unique_ptr" è stato progettato per comportarsi in quel modo . Se vuoi un po 'di sentimento "sotto il cofano", pubblica solo una possibile implementazione di "unique_ptr". Solo i miei 2 centesimi. – gigabytes

4

Non vi è alcuna perdita di memoria qui, l'assegnazione assegnerà le risorse associate alla prima allocazione. Probabilmente il non vederlo nel debugger significa che la chiamata pertinente è stata appena ottimizzata. Prova a compilare con -O0 se vuoi vederlo.

+0

Sto usando VC++ 2015, sto eseguendo il debug di build di debug. Ho visto la classe 'unique_ptr' e ho impostato i punti di interruzione - sono stati disabilitati (anche se altre parti dell'intestazione' memory' colpiscono i punti di interruzione.) Dunque, devi avere ragione – Ajay

5

Spostare operatore di assegnazione è chiamato, che fa

if (this != &_Right) 
{ // different, do the swap 
    reset(_Right.release()); 
    this->get_deleter() = _STD move(_Right.get_deleter()); 
} 

No perdita qui, come fa reset, che sarà deallocare.