gpt4 book ai didi

c++ - 使用默认构造函数返回临时对象时,析构函数调用两次

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:21:08 25 4
gpt4 key购买 nike

问题

析构函数在以下代码中被调用了两次:

class Foo
{
public:
~Foo()
{
std::cout << "Destructor called\n";
}

Foo& operator=(const Foo& other)
{
std::cout << "Assignment called\n";

return *this;
}
};

Foo foo()
{
return Foo();
}

int main()
{
foo();

return 0;
}

输出:

Destructor called
Destructor called

我怀疑这是由于对赋值运算符或复制构造函数的隐式调用所致。我无法判断是否调用了复制构造函数,因为添加任何类型的构造函数都神奇地解决了问题(如下所述),但至少不会调用赋值运算符。

如前所述,如果我添加一个构造函数,问题就会消失:

class Foo
{
public:
Foo()
{
std::cout << "Constructor called\n";
}

Foo(const Foo& other)
{
std::cout << "Copy constructor called\n";
}

~Foo()
{
std::cout << "Destructor called\n";
}

Foo& operator=(const Foo& other)
{
std::cout << "Assignment called\n";

return *this;
}
};

输出变为:

Constructor called
Destructor called

如果我返回一个引用而不是一个对象,问题也会消失(但会导致“返回局部或临时变量的地址”警告):

Foo& foo()
{
return Foo();
}

问题

为什么析构函数被调用两次,为什么使用默认构造函数时行为不同?是否有合乎逻辑的解释,或者可能是编译器的错误?

我正在使用 MSVC 2013,如果它能有所作为的话。

最佳答案

Foo foo()
{
return Foo(); // temporary is created and copied into the return value.
// The temporary gets destroyed at the end of the copy constructor.
}

int main()
{
foo(); // discarded-value expression; the return value gets destroyed immediately.
}

允许编译器应用复制省略 - 在这种情况下,NRVO (§12.8/31):

— when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same cv-unqualified type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move

请注意,无论复制构造函数是否有任何副作用,这都有效。这是一种“优化”,可以在不违反标准的情况下合法地改变程序的可观察行为。

由于编译器没有义务优化任何东西,结果可能因代码(和优化级别)而异。

关于c++ - 使用默认构造函数返回临时对象时,析构函数调用两次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26193117/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com