我有以下代码,想知道何时调用Foo的析构函数。
#include <iostream>
class Foo {
public:
Foo() {
}
~Foo() {
std::cout << "destruct" << std::endl;
}
};
void go(Foo f) {
std::cout << "go" << std::endl;
}
int main() {
go(Foo());
std::cout << "main" << std::endl;
return 0;
}
如果我运行代码,我得到以下输出
go
destruct
main
它表明在完成后调用Foo的析构函数。我的gcc是4.8.3。
我原以为临时Foo的对象在被复制到go的参数后应该被删除。但情况并非如此,只有Foo的一个对象存在。在编译器的实现方面,这是预期的还是未定义的?
答案 0 :(得分:1)
这是C ++标准允许的优化。
C ++标准草案,[class.temp/2]说和我引用(仅限相关部分;重点是我的):
临时对象的具体化通常会延迟一段时间 尽可能避免创建不必要的临时对象。 .....
示例:
class X { public: X(int); X(const X&); X& operator=(const X&); ~X(); }; class Y { public: Y(int); Y(Y&&); ~Y(); }; X f(X); Y g(Y); void h() { X a(1); X b = f(X(2)); Y c = g(Y(3)); a = f(a); }
X(2)
是在用于保存f()
参数的空间中构建的Y(3)
是在用于保存g()
参数的空间中构建的。
以前,在n3690,它说:
实现可能会使用临时构造
X(2)
在使用f()
的复制构造函数将其传递给X
之前; 或者,X(2)
可能会在用于保留的空间中构建 论证
这意味着,这个:
void go(Foo) {
std::cout << "go" << std::endl;
}
int main() {
go(Foo());
}
有时为&#34;表演者&#34;如你所愿!看,C ++逐渐到达那里;-)。
但是你知道,使用std::move
会禁止这种行为,因为std::move
会从materialized对象产生xvalue
表达式:
void go(Foo) {
std::cout << "go" << std::endl;
}
int main() {
go(std::move(Foo()));
}
总之,
在您的案例中未使用std::move
时,对象的创建时间为Live on Coliru
但是当你使用std::move
时,它会被创建两次Live on Coliru,这是因为对象的具体化。阅读class.temp/2的完整段落,了解具体化的含义。