2016-09-26 7 views
0

最近、私はunique_ptrの使用法について学びました。STLコンテナのストアバイバリューの性質から生まれるコピーオーバーヘッドを取り除くことを望んでいました。しかし、私は本当に奇妙な動作に遭遇し、理由を理解できませんでした。ベクトル内の "unique_ptr"の予期せぬオーバーライト

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

私の質問は、なぜ各push_backは、前回と同じが押されているすべてのオブジェクトを作るので、その前にすべてのアイテムを交換しないで

[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 

次のように出力されていますmake_uniqueを使用するか、さらに良い - この場合にはLargeObjはあなたがnewによって返されたポインタではなく、スタック変数のアドレスからunique_ptrを構築すべきであるID 9.

答えて

0

です。また、一貫してstd::cout、または一貫してprintfを使用するようにしてください。もう一度やり直してください:

#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; 
} 

LargeObj(スタックに1つしかありません)という問題がありました。ループのたびに同じメモリがLargeObjとしてスタックに構築され、ループの最後にLargeObjが破壊されました(デストラクタが呼び出されました)。ループの後、スタックの(非)ランダムビットの内容を出力します。厳密に言えば、これは未定義の動作であり、何かが起こる可能性があります。しかし、保存した最後のIDの値を印刷することは特に驚くべき結果ではありません。

未定義の動作を予測する場合:これはデバッグ時に便利なことです(コードの動作を理解できるようになります)が、極端にコードを書くのは危険です。それは想像を絶する最も奇妙で助けになる方法で変わるでしょう。

はまた、私は、ヘッダーが含まれているので、これはMinimal, Complete, and Verifiable Exampleなり(とstd::を使用し、ループのための反復を使用することに注意してください。

+0

私は本当にあなたの詳細な回答と私の文法の訂正を認めます。 –