2017-06-04 6 views
0
#include <iostream> 
#include <vector> 

struct T{ 
    T(){ 
     std::cout << "Constructor\n"; 
    } 
    ~T(){ 
     std::cout << "Destructor\n"; 
    } 
}; 

int main() { 
    std::vector<T> vec; 
    vec.push_back(T()); 
    vec.push_back(T()); 

    return 0; 
} 

出力は次のようになります。なぜemplace_backが関係するのですか?

(1)Constructor 
(2)Destructor 
(3)Constructor 
(4)Destructor 
(5)Destructor 
(6)Destructor 
(7)Destructor 

そんなにdesructorsコールがあるのはなぜ?私が見ること:

(1)consruct一時オブジェクトTEMP1

(2)消滅TEMP1

(3)consruct一時オブジェクトTEMP2

(4)消滅TEMP2

それをコピーコンストラクタを呼ばれるか、(5)と(6)明確であり、TEMP1ので、一時2のコンストラクタを動かしました。しかし、(7)についてはどうですか?

+9

コピーコンストラクタもインストルメントします。照らし出すかもしれない。また、 'push_back'呼び出しの前、後、間に何かを表示するのに役立ちます。このようにすれば、どのようなアクションに応答して、これらのコンストラクタとデストラクタがいつ発生するかを知ることができます。 –

+3

emplace_backを一度、push_backを一度呼び出すことを意味しましたか? push_backを2回呼び出すポイントが表示されず、タイトルと一致しません。 –

+0

ベクトルが記憶域を拡張する必要がある場合、ベクトルは新しい(大きな)チャンクを割り当て、元の要素を新しい記憶域にコピーまたは移動した後、元のファイルを破棄して古いメモリを解放します。余分なデストラクタ呼び出しは、おそらくそれに由来します。 –

答えて

3

のは、あなたの構造ビットを拡張してみましょう:push_back方法に

struct T { 
    T() { 
     std::cout << "Constructor\n"; 
    } 

    T(const T&) { 
     std::cout << "Copy Constructor\n"; 
    } 

    T(T&&) { 
     std::cout << "Move Constructor\n"; 
    } 

    ~T() { 
     std::cout << "Destructor\n"; 
    } 
}; 

、別のコール:

vec.push_back(T()); // 1 
std::cout << "--- --- ---\n"; 

vec.push_back(T()); // 2 
std::cout << "--- --- ---\n"; 

今、出力がより完全になります。

Constructor 
Move Constructor 
Destructor 
--- --- --- 
Constructor 
Move Constructor 
Copy Constructor 
Destructor 
Destructor 
--- --- --- 
Destructor 
Destructor 

最初のグループ:

210は、第1のpush_back呼び出しに対応する:

vec.push_back(T()); // 1 

出力を容易に解読されるかもしれない:

Constructor // Create a temporary 
Move Constructor // Move a temporary into the internal vector storage 
Destructor // Destroy a temporary 

第二群:

Constructor 
Move Constructor 
Copy Constructor 
Destructor 
Destructor 

は、第push_back呼び出しに対応:

vec.push_back(T()); // 2 

ともう少し複雑:

Constructor // create a temporary 
Move Constructor // move it into the newly allocated vector storage 
Copy Constructor // copy previously created element into the new storage 
Destructor // destroy old storage 
Destructor // destroy temporary 

ここでは、ベクトルクラスは内部的にそのメモリを割り当て、すべての要素のenoghスペースを提供するために、それを管理していることを忘れてはなりません。だから、あなたはより多くの要素を追加する場合、新しい割り当てが起こると、古い要素をコピーまたは新しいストレージに移動されます。

既知のサイズの場合は、あなたは、単に要素の特定の数のための十分なメモリを確保しreserve方法を、使用することがあります。それは(少なくともまで、あなたが予約サイズを超えない)ベクターに新しい要素を追加することでこれらの再配分中の不要なメモリ再割り当ておよびコピーまたは移動要素を避けることができます。

第三の群:

Destructor 
Destructor 

は、プログラムの終了時にベクトルvecデストラクタコールに対応します。

+0

これは、3/5/0のルールを守らなければ、テストコードでさえもお尻を噛む可能性があり、それに追いついて混乱を避ける方法を再び示しています。 –

+0

良い答え。 'std :: vector :: reserve'がどのように影響を与えるかを見てみるといいかもしれません(非常にベクトルが「内部メモリを割り当てて管理する」というあなたのコメントに非常に関係しています)。 – erip

+0

@eripええ、私は答えを修正しました) –

0

emplace_back( "std :: unique_ptr"のような) "移動のみ"のタイプの問題です。

これは間違っており、簡略化されています。すべてのコンテナが均等に作成されるわけではありません。我々はreserveを使用する場合は、あなたのベクトル例えば、実装は、私たちのコピー/余分なデストラクタをeliding、移動アサインではなく、構造の操作を行うことができます

std::vector<T> v; 
v.reserve(2); 
v.emplace_back(1); 
v.emplace_back(1); 

出力:

Constructor 
Constructor 
--- 
Destructor 
Destructor 

セットの場合:

std::set<T> s; 
s.emplace(1); 
s.emplace(1); 

同じ出力が得られます。どうして?集合は固有な権利なので、理論的には1つのオブジェクトしか構築できませんか?実際には、典型的な実装は、比較を実行するために一時的なノードを構築し、コンテナに入ることはないとしても余分な構成/破壊を考慮する。

+0

それは_question_とどう関係していますか?あなたがコメントに答えるなら、コメントセクションでそれをしてください、答えではありません。 –

+0

@Revolver_Ocelot私は自分の答えにコメントを引用したので、すみません。私は、あなたがここに警察官を派遣してくれてうれしいです。 – user8110786

関連する問題