临时对象未正确销毁

Temporary object not destroyed correctly?

本文关键字:临时对象      更新时间:2023-10-16

请在此处查看此代码:

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对象被破坏时完成的。但这还可以吗?

这是否意味着临时对象不调用析构函数

有争议的一句话是:

test var = 123;

我相信,相关的标准文本(评论中的专家们引用的)是(8.5,"声明人"):

调用所选函数时,将初始值设定项表达式作为其参数;如果函数是一个构造函数,则调用会初始化目标类型的cv非alified版本的临时版本。临时值是一个值。调用的结果(对于构造函数来说是临时的)然后用于根据上面的规则直接初始化作为复制初始化目标的对象。在某些情况下,允许实现通过将中间结果直接构造到正在初始化的对象中来消除此直接初始化中固有的复制

事实上,在12.6中,我们得到了一个例子:

complex f = 3;  // construct complex(3) using
                // complex(double)
                // copy it into f

因此,在使用=时,您的实现可能是直接构建对象并完全消除中间临时对象(正如注释所指出的,大多数都是这样做的)。

这个类没有正确复制,所以创建它的副本(以及释放副本和原始副本)会导致双重删除(以及崩溃、未定义的行为等)。因为没有创建副本,所以上面不会发生这种情况。

两点:首先,在这种特殊情况下,允许编译器通过对标准我熟悉的所有编译器都有。你可以验证是否通过定义复制构造函数在代码中发生这种情况

第二,如果临时的没有优化,你的代码未定义的行为。双重删除可以有任何可以想象的行为:立即崩溃,自由空间竞技场的腐败(导致如果程序继续运行,很晚就会崩溃),没有效果永远,或其他任何事情。事实上,你没有看到任何症状并不意味着代码是正确的。

代码没有爆炸并不意味着它是正确的。

您的类有缺陷,因为它很容易受到您所描述的双deletes的影响。

例如,将var.show();更改为以下内容:

    test(var).show();

使代码在我的计算机上可靠地爆炸。

若要修复此问题,请实现复制构造函数和赋值运算符。