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

test编译后,会创建一个 id 为 4的临时实例。

然后,调用赋值运算符。由于您没有提供,因此编译器为您生成了一个,如下所示:

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

id 1 简单地被临时的 4 覆盖,对于集合赋值,std::vector调用赋值运算符 of。

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 将被 4 覆盖,这就是为什么您将最后一个视为:

dying: 4
于 2012-08-17T10:47:14.870 回答
0

关于实践中的行为,声明

    obj = test(4);

id将成员的值更改为4。因此,当该对象被销毁时,它会报告具有 id 的对象4已被销毁。由于您尚未定义复制分配运算符,因此该分配执行按成员分配。

关于正式保证的行为"stdafx.h",只有在代码中的非标准标头定义了宏_tmain并且_TCHAR预处理产生标准main要求的标准函数时,您才具有(对于托管实现) :

C++11 §3.6.1/1
“程序应包含一个名为 的全局函数main,它是程序的指定开始。是否需要独立环境中的程序来定义主要功能是由实现定义的。”

虽然不太可能,但这意味着如果标头没有适当地定义这些宏,那么原则上,无论其余代码如何,您可以获得您看到的输出。

确保不发生未定义行为的一种方法是简单地使用标准main.

毕竟,截至 2012 年,使用那些旨在支持 Windows 9x 的 Microsoft 宏绝对没有优势,尤其是考虑到 Microsoft 使用 Unicode 层,在 2001 年就已经过时了这些宏。

即,在 10 年后继续使用它们,只是毫无意义的混淆和额外的工作,包括你不能正式地说你的程序必须产生任何特定的结果。

于 2012-08-17T11:30:06.713 回答
0

你看不到 1 因为你在最后破坏了 obj 。在你用 test(4) 重写它之前。因此 1 被 4 重写。

于 2012-08-17T10:47:19.693 回答