请在此处查看此代码:
class test
{
int n;
int *j;
public:
test(int m)
{
n = 12;
j = new int;
cin >> *j;
}
void show()
{
cout << n << ' ' << *j << endl;
}
~test()
{
delete j;
}
};
int main()
{
test var = 123;
var.show();
return 0;
}
在这个程序中,编译器应该抱怨双重删除j
。首次删除是在销毁临时对象temporary(123)
时完成的。第二次删除是在var
对象被销毁时完成的。但这工作正常吗?
是否意味着临时对象不会调用析构函数?
答案 0 :(得分:8)
有争议的一句是:
test var = 123;
我认为,相关的标准文本(评论中的专家正在引用)是(8.5,“声明者”):
使用初始化表达式作为参数调用所选函数;如果函数是构造函数,则调用初始化目标类型的cv-unquali fi ed版本的临时版本。临时是一个右值。然后,根据上述规则,调用的结果(对于构造函数的情况是临时的)用于直接初始化作为复制初始化目标的对象。在某些情况下,允许实现通过将中间结果直接构造到正在初始化的对象中来消除此直接初始化中固有的复制;
事实上,在12.6中,我们得到了一个例子:
complex f = 3; // construct complex(3) using
// complex(double)
// copy it into f
因此,在使用=
时,您的实现可能直接构造对象并完全消除中间临时(并且正如评论所指出的那样,大多数都是这样做)。
此类不能正确复制,因此创建它的副本(以及释放副本和原始文件)将导致双重删除(以及崩溃,未定义的行为等)。由于没有创建副本,因此上述情况不会发生。
答案 1 :(得分:2)
两点:首先,在这种特殊情况下,允许编译器 通过明确授权优化临时 标准。我熟悉的所有编译器都可以。你可以验证 是否通过定义复制构造函数在代码中发生这种情况 并检测它。
其次是如果临时没有优化,你的代码就有了 未定义的行为。双删除可以有任何可以想象的行为: 立即崩溃,自由空间舞台的腐败(导致一个 如果程序继续运行,以后会崩溃),没有效果 永远,或其他任何东西。事实上你没有看到任何症状 并不意味着代码是正确的。
答案 2 :(得分:1)
代码没有爆炸的事实并不意味着它是正确的。
你的课程有问题,因为它很容易以你描述的方式加倍deletes
。
例如,将var.show();
更改为以下内容:
test(var).show();
使代码在我的计算机上可靠地爆炸。
要修复,请实现复制构造函数和赋值运算符。