我做了以下简短的代码进行实验,并尝试获得“第一手”体验,当对象的构造函数和析构函数被调用时:
class Foo
{
public:
Foo(int bar)
{
this->bar = bar;
std::cout << "Standard constructor called" << std::endl;
}
~Foo()
{
std::cout << "Standard destructor called" << std::endl;
}
Foo(const Foo &foo)
{
std::cout << "Copy constructor called" << std::endl;
this->bar = foo.bar;
}
inline int get_bar() { return bar; }
private:
int bar;
};
Foo make_foo(int bar)
{
Foo f1(bar);
std::cout << "About to return foo with address of: " << &f1 << std::endl;
return f1;
}
int main()
{
Foo f2 = make_foo(3);
std::cout << "New variable has address of: " << &f2 << std::endl;
std::cout << "And a value of " << f2.get_bar() << std::endl;
}
但是当我运行此代码时,我发现奇怪的事情。与预期一样,打印“标准构造函数”,并打印该函数中foo的地址。但是当函数结束时,没有析构函数被调用,并且f2实际上具有与f1相同的内存地址,即使从我的理解中,f1应该超出范围并释放其内存,因为它在堆栈上,对吧?或者这不是这种情况下的预期结果?
我的期望是复制构造函数将被调用以便将f1复制到f2,然后f1将调用其析构函数,并且f2将占用不同的内存地址。
如果有人好奇,这是实际输出:
Standard constructor called
About to return new foo with address of: 0x7fff518e5a88
New variable has address of: 0x7fff518e5a88
And a value of 3
Standard destructor called
有趣的是,当我将make_foo
的返回类型更改为引用类型时,该函数几乎按照我的预期执行,f1被破坏,f2复制垃圾数据。
这是一些特殊情况,当堆栈中的变量被返回分配给我应该知道的另一个变量时,堆栈中的变量不会释放其内存吗?
答案 0 :(得分:5)
编译器正在执行返回值优化(RVO)。你可以在这里读到它: https://en.wikipedia.org/wiki/Copy_elision#Return_value_optimization