2016-06-14 9 views
6

Ich verstehe nicht, was folgende Anweisung tun würde (besonders zweite Zeile)?Neu zuordnen des Objekts unique_ptr mit make_unique-Anweisungen - Speicherleck?

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

Wird der zweite Aufruf von make_unique durch Zuweisungsoperator gefolgt wird de-allocate Speicher von ersten Anruf zugeordnet ist, oder wird es Speicherleck sein? Muss ich buff.reset(new int[512]); verwenden?

Ich habe es debuggt, aber keine operator= aufgerufen, noch ein Destruktor aufgerufen (von unique_ptr).

+0

Ich wette der Compiler einfach den ersten Aufruf. – kennytm

+0

'operator =' sollte aufgerufen werden und das zuvor verwaltete Objekt wird gelöscht. Kein Speicherleck hier. – songyuanyao

+0

Die Deklaration weist ein Array von Integer der Größe 512 zu. Der hier aufgerufene Destruktor wird "Delete Buff" verwenden, um Speicher freizugeben, aber Sie haben Speicher für ein Array von Integer zugewiesen, idealerweise sollte "delete [] buff" aufgerufen werden. Für diese Anforderung können Sie einen benutzerdefinierten Deallocator mit Ihrer Smart-Pointer-Deklaration übergeben. – sagar

Antwort

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()); 
} 

ergibt Montage:

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

Eine Erläuterung, wie intelligente Zeiger funktionieren und warum es kein Leck gibt waren meiner Meinung nach nützlicher als eine Menge compilerspezifischer Assembly-Ausgabe – gigabytes

+0

@gigabytes verzeih mir Ich habe 1981 im Assembler programmieren gelernt.Es war meine erste Computersprache, also neige ich dazu, jede andere Sprache in Bezug darauf zu sehen Ich nahm an, dass eine kommentierte Versammlung die beste Erklärung wäre. Was habe ich noch unklar? –

+0

Zu schließen, dass diese beiden Zeilen tatsächlich "new" und "delete" wie erwartet heißen, wäre ausreichend gewesen, um 'printf'-Anweisungen in Konstruktoren und Destruktoren zu setzen , nachdem sichergestellt wurde, dass der Compiler überhaupt Code ausgab wie Sie, ohne auf asm zurückzugreifen.Aber für jemanden, der diese Frage stellt, ist es nützlicher zu wissen, * warum * das der Fall ist, das heißt, dass der Standard sagt, dass 'unique_ptr' sich so verhält, und die Gründe warum 'unique_ptr' so entworfen wurde . Wenn Sie etwas "unter der Haube" fühlen möchten, veröffentlichen Sie einfach eine mögliche Implementierung von 'unique_ptr'. Nur meine 2 Cent. – gigabytes

4

Hier gibt es kein Speicherleck, die Zuordnung hebt die Ressourcen auf, die der ersten Zuweisung zugeordnet sind. Wenn Sie es im Debugger nicht sehen, bedeutet dies höchstwahrscheinlich, dass der entsprechende Anruf gerade optimiert wurde. Versuchen Sie, mit -O0 zu kompilieren, wenn Sie es sehen möchten.

+0

Ich benutze VC++ 2015, ich bin Debug Debug Build. Ich sah 'unique_ptr'-Klasse und setzte dort Haltepunkte - sie werden deaktiviert (obwohl andere Teile von' memory'-Header die Haltepunkte treffen. Daher müssen Sie recht haben. – Ajay

5

Verschieben Zuweisungsoperator aufgerufen, die tut

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

Kein Leck hier, wie es zurückgesetzt tut, das wird freischalten.

Verwandte Themen