堆栈上的对象被覆盖时未调用析构函数
Destructor not called when object on stack is overwritten
今天我想知道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 overwriten";
obj = test(4);
cout << "before scope exitn";
}
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的测试对象的析构函数?如果它的析构函数在被覆盖时没有被调用,那么什么会调用它向量中实例的析构因子呢?
您创建了一个析构函数,但没有赋值运算符,这违反了三规则。
通过阅读,您可以如下解释您的代码:
当线路
obj = test(4);
则创建id为4的test
的临时实例。
然后,调用赋值运算符。由于您没有提供,编译器为您生成了一个如下所示的
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
再次输出。
这是因为您没有实现赋值运算符,所以改为执行成员赋值。所以这行:
obj = test(4);
使得第一个对象(test obj(1)
)中的CCD_ 5被重写为CCD_。最后一行dying: 4
来自于摧毁那个物体。
obj
不会被破坏:
obj = test(4);
所有发生的事情都是创建一个test(4)
并将其分配到现有对象上,因此1的id
将被4覆盖,这就是为什么您将最后一个显示为:
dying: 4
您看不到1,因为您在最后销毁了obj。在你通过测试(4)重写它之前。因此,1被4重写。
关于实践中的行为,语句
obj = test(4);
将CCD_ 12成员的值改变为CCD_。因此,当该对象被销毁时,它报告id为4
的对象被销毁。分配执行成员分配,因为您尚未定义复制分配运算符。
关于形式上保证的行为,只有当代码中的非标准"stdafx.h"
标头定义了宏_tmain
和_TCHAR
,使得预处理产生标准所需的标准main
函数时,才有这种能力(对于托管实现):
C++11§3.6.1/1:
“程序应包含一个名为main
的全局函数,该函数是程序的指定起点。它实现定义了是否需要独立环境中的程序来定义主函数”
虽然不太可能,但这意味着,如果标头没有适当地定义这些宏,那么原则上,无论代码的其余部分是什么,都可以获得您看到的输出。
确保未定义行为不会发生的一种方法是简单地使用标准main
。
毕竟,截至2012年,使用那些旨在支持Windows 9x的Microsoft宏绝对没有优势,尤其是考虑到微软在2001年就已经使用了Unicode层,使这些宏过时。
也就是说,在10年后继续使用它们,只是毫无意义的混淆和增加工作,包括你不能正式说你的程序必须产生任何特定的结果。
- 什么时候调用析构函数
- C++-明确何时以及如何调用析构函数
- C++ 防止在映射中放置()时调用析构函数
- 调用析构函数以释放动态分配的内存
- C++:使用方法调用析构函数的顺序是什么?
- 向量推回调用析构函数时调用析构函数
- 如何在调用析构函数时优雅地停止/销毁带有阻塞调用C++线程?
- C++,我应该调用析构函数吗?
- 如何获取有关在 Clang LibTooling 中调用析构函数的信息?
- 当我从 std::vector 中的新放置调用析构函数时会发生什么?
- 为什么这里不调用析构函数
- 在调用 std::bind 的产品后意外调用析构函数
- 为什么在传递给函数而不是构造函数时调用析构函数?
- 如何在C++中调用析构函数
- 为什么为未删除的对象调用析构函数?
- 调用析构函数时出错
- C++ 在不释放内存的情况下调用析构函数
- 为什么在运算符删除中不调用析构函数?
- C++ 调用析构函数后动态模板队列"double free or corruption (out)"
- 在 postOrderDelete 上调用析构函数时引发的异常