2016-09-26 2 views
0

Ich habe kürzlich über die Verwendung von unique_ptr in der Hoffnung gelernt, dass ich den Kopieraufwand loswerden kann, der von der Store-by-Value-Eigenschaft von STL-Containern herrührt. Jedoch bin ich auf ein wirklich seltsames Verhalten gestoßen und konnte nicht herausfinden warum.Unerwartetes Überschreiben von "unique_ptr" in Vektor

struct LargeObj 
{ 
    int id; 
    LargeObj(int _id) : id(_id) 
    { 
     cout << "[" << this << "] is constructed\n"; 
    } 
    ~LargeObj() 
    { 
     cout << "[" << this << "] is destroyed\n"; 
    } 
    // Simulate huge data size 
    int data[10000]; 
}; 

int main(int argc, char **argv) 
{ 
    vector<unique_ptr<LargeObj>> store_by_pointer; 
    for (int i = 0; i < 10; i++) 
    { 
     LargeObj obj(i); 
     store_by_pointer.push_back(unique_ptr<LargeObj>(&obj)); 
    } 
    for (auto ite = store_by_pointer.begin(); ite != store_by_pointer.end(); ite++) 
    { 
     printf("ID: %d\n", (*ite)->id); 
    } 
    return 0; 
} 

Die Ausgabe ist wie folgt

[00000000001A6180] is constructed 
[00000000001A6180] is destroyed 
[00000000001A6180] is constructed 
[00000000001A6180] is destroyed 
[00000000001A6180] is constructed 
[00000000001A6180] is destroyed 
[00000000001A6180] is constructed 
[00000000001A6180] is destroyed 
[00000000001A6180] is constructed 
[00000000001A6180] is destroyed 
[00000000001A6180] is constructed 
[00000000001A6180] is destroyed 
[00000000001A6180] is constructed 
[00000000001A6180] is destroyed 
[00000000001A6180] is constructed 
[00000000001A6180] is destroyed 
[00000000001A6180] is constructed 
[00000000001A6180] is destroyed 
[00000000001A6180] is constructed 
[00000000001A6180] is destroyed 
ID: 9 
ID: 9 
ID: 9 
ID: 9 
ID: 9 
ID: 9 
ID: 9 
ID: 9 
ID: 9 
ID: 9 

Meine Frage ist, warum jeder push_back alle Elemente vor ersetzen und damit alle Objekte machen das gleiche wie das letzte geschoben wird, die in diesem Fall ist die LargeObj mit ID 9.

Antwort

0

Sie unique_ptr aus dem Zeiger von new, nicht die Adresse eines Stapels Variable zurückgegeben bauen sollte - oder noch besser, verwenden make_unique. Sie sollten auch sicherstellen, std::cout konsistent oder printf konsequent zu verwenden. Versuchen Sie es erneut mit:

#include <vector> 
#include <memory> 
#include <iostream> 

struct LargeObj 
{ 
    int id; 
    LargeObj(int _id) : id(_id) 
    { 
     std::cout << "[" << this << "] is constructed\n"; 
    } 
    ~LargeObj() 
    { 
     std::cout << "[" << this << "] is destroyed\n"; 
    } 
    // Simulate huge data size 
    int data[10000]; 
}; 

int main(int argc, char **argv) 
{ 
    std::vector<std::unique_ptr<LargeObj>> store_by_pointer; 
    for (int i = 0; i < 10; i++) 
    { 
     store_by_pointer.push_back(std::make_unique<LargeObj>(i)); 
    } 
    for (const auto& ptr : store_by_pointer) 
    { 
     std::cout << "ID: " << ptr->id << "\n"; 
    } 
    return 0; 
} 

Ihr Problem war, dass es nur eine LargeObj war (auf dem Stack). Jedesmal um die Schleife herum wurde das gleiche Stück Speicher auf dem Stapel erstellt wie die LargeObj, und am Ende der Schleife wurde die LargeObj zerstört (der Destruktor genannt). Nach der Schleife haben Sie den Inhalt eines (nicht) zufälligen Bitstapels ausgedruckt; streng genommen ist dies ein undefiniertes Verhalten, und irgendetwas kann passieren. Das Ausdrucken des Wertes der letzten ID, die Sie gespeichert haben, ist jedoch kein besonders überraschendes Ergebnis.

Bei der Vorhersage, was undefiniertes Verhalten tun: Dies ist eine nützliche Sache beim Debuggen (so können Sie das Verhalten Ihres Codes verstehen), aber es ist extrem gefährlich, den Code zu schreiben, um sich darauf zu verlassen. Es wird sich ändern - in den bizarrsten und wenig hilfreichsten Wegen, die man sich vorstellen kann.

Beachten Sie auch, dass ich die Header enthalten haben, so wird dies eine Minimal, Complete, and Verifiable Example (und verwendet std:: und das Iterieren for-Schleife verwenden.

+0

Ich schätze Ihre ausführliche Antwort und die Korrektur meiner Grammatik wirklich. –

Verwandte Themen