6

今日、私はc ++デストラクタについて疑問に思っていたので、小さなテストプログラムを作成しました。それは私の最初の質問に答えましたが、次のような新しい質問を提起しました:
次のプログラム:

#include "stdafx.h"
#include <vector>
#include <iostream>
using namespace std;
class test
{
public:
    int id;
    vector<test> collection;
    test(){}
    test(int id_in){id = id_in;}
    ~test(){cout << "dying: " << id << "\n";}
};

int _tmain(int argc, _TCHAR* argv[])
{
    {
        test obj(1);
        obj.collection.push_back(test(2));
        obj.collection.push_back(test(3));
        cout << "before overwrite\n";
        obj = test(4);
        cout << "before scope exit\n";
    }
    int x;
    cin >> x;
}

次の出力を生成します。

dying: 2
dying: 2
dying: 3
before overwrite
dying: 2
dying: 3
dying: 4
before scope exit
dying: 4

ID 1のテストオブジェクトのデストラクタが表示されないのはなぜですか?上書きされたときにそのデストラクタが呼び出されない場合、そのベクトル内のインスタンスのデストラクタを呼び出すのは何ですか?

4

5 に答える 5

6

これは、代入演算子が実装されていないため、代わりにメンバーごとの代入が行われるためです。したがって、この行:

obj = test(4);

id最初のオブジェクト( )がtest obj(1)に上書きされ4ます。最後の行dying: 4は、まさにそのオブジェクトを破壊することからです。

于 2012-08-17T10:44:42.697 に答える
6

デストラクタを作成することで三つのルールに違反しますが、代入演算子は作成しません。

それを読むことで、コードを次のように解釈できます。

ラインが

obj = test(4);

がコンパイルされると、の一時インスタンスがtestID4で作成されます。

次に、代入演算子が呼び出されます。提供しなかったため、コンパイラは次のようなものを生成しました。

test& operator=(const test& other)
{
    id = other.id;
    collection = other.collection;
    return *this;
}

id 1は、一時的な4で単純に上書きされ、コレクションの代入では、の代入演算子std::vectorが呼び出されます。

std::vectorの代入演算子は、以前に含まれていたすべての要素を削除します。これが、次のように表示される理由です。

dying: 2
dying: 3

出力で。最後に、ID 4で一時的に作成されたobjインスタンスが削除され、

dying: 4

初めて登場します。obj範囲外になると、

dying: 4

もう一度出力します。

于 2012-08-17T10:47:48.530 に答える
3

objこれを行っても破壊されません:

obj = test(4);

発生しているのは、atest(4)が作成されて既存のオブジェクトに割り当てられているため、id1の1が4で上書きされるため、最後のオブジェクトは次のように表示されます。

dying: 4
于 2012-08-17T10:47:14.870 に答える
0

最後にobjを破棄するため、1は表示されません。そして、test(4)で書き直す前に。したがって、1は4で書き換えられます。

于 2012-08-17T10:47:19.693 に答える
0

実践中の行動に関して、声明

    obj = test(4);

idメンバーの値をに変更します4。したがって、そのオブジェクトが破棄されると、idを持つオブジェクトが破棄されたことが報告4されます。コピー代入演算子を定義していないため、代入はメンバーごとの代入を実行します。

正式に保証された動作に関しては、コード内の非標準"stdafx.h"ヘッダーがマクロ_tmainを定義し、_TCHAR前処理mainによって標準で要求される標準関数が生成される場合にのみ、(ホストされた実装の場合)それがあります。

C++11§3.6.1/1: 「プログラムには、プログラムの指定された開始点である、
と呼ばれるグローバル関数が含まれている必要があります。main主な機能を定義するために自立環境のプログラムが必要かどうかは、実装によって定義されます。」

可能性は低いですが、これは、ヘッダーがこれらのマクロを適切に定義していない場合、原則として、コードの残りの部分に関係なく、表示される出力を取得できることを意味します。

未定義の動作が発生しないようにする1つの方法は、単に標準を使用することmainです。

結局のところ、2012年の時点で、Windows 9xをサポートするように設計されたMicrosoftマクロを使用することにまったく利点はありません。特に、MicrosoftがLayer for Unicodeを使用して、これらのマクロを2001年にすでに廃止したことを考えると。

つまり、10年以上使用し続けることは、プログラムが特定の結果を生成する必要があると正式に言うことができないことを含め、単に無意味な難読化と追加作業です。

于 2012-08-17T11:30:06.713 に答える