2016-08-18 3 views
1

これは異なるはずだと確信していたので、混乱しました。このコード例を見てみましょう:新しく割り当てられる前にオブジェクトが削除されていない

#include <iostream> 
#include <string> 

using namespace std; 

class base 
{ 
    public: 
    virtual ~base() = default; 
}; 

class derived : public base 
{ 
    private: 
    int a = 0; 
    int *b = nullptr; 
    std::string lol; 

    public: 
    derived(std::string s) : b(new int(6)), lol{s} { cout << "ctor " << lol << endl; } 
    derived(derived const& d) : lol{d.lol + " copy"} {cout << "copy " << lol << endl; } 

    virtual ~derived() { cout << "dtor " << lol << endl; delete b; } 

    virtual void superFunction() { cout << "OMG " << lol << endl; } 
}; 

int main() 
{ 
    derived a("a"); 
    derived b("b"); 
    a = b; 
} 

そして、すべての最適化をオフにした状態でプログラムの出力は次のようになります。

ctor a 
ctor b 
dtor b 
dtor b 

私はこのケースでは、コンパイラはオブジェクトaを削除し、コピーを使用するコードを生成する必要があることを確信していました新しいオブジェクトを作成するコンストラクタです。代わりに暗黙的に宣言するoperator=を使用します。

誰かが理由を説明できますか?または、私にC++標準を指摘してください。

ありがとうございました。

+1

"コンパイラ"が最初に 'a'を削除した場合、' b'に何をコピーしますか?とにかく、ここにコピーはなく、割り当てだけです。 – juanchopanza

+0

関連:https://stackoverflow.com/questions/4172722/what-is-the-rule-of-three – vu1p3n0x

答えて

5

a = b;と記述すると、コードに存在せず削除されていないと自動的に生成されます。コピーコンストラクタは、あなたがにしようとする場合にのみ使用され、このような別のオブジェクトから新しいオブジェクトを初期化します。それはbを削除しようとして、あなたのコードがクラッシュしたから、同じメモリを指して、メインが戻る前に、また

derived a("a"); 
derived b = a; 

aとの後にa = b;のデフォルト割り当て。

aderivedデストラクタで削除する場合は、a = b;の実行後に必要なのはコピーアンドスワップイディオムだけです。 What is the copy and swap idiom?には、レガシーで現代的なC++でこれを行う方法に関する素晴らしい答えがあります。その答えからの4のルールの適切な実装は、DRYの原則に完全に適合し、メモリの問題を回避するのに役立ちます。パラメータをoperator=に値で渡すと、コンパイラは適切なコンストラクタ(コピーまたは移動)を選択し、すべてfiveの代わりに4つのメソッドしか書くことができないという素晴らしいトリックに注意してください。

関連する問題