此页面是 Microsoft 特定的。确实,标准允许在函数返回期间对复制构造函数进行两次、一次或零次调用(这称为复制省略)。事实上,一个电话就足够了。
假设你写:
A f(int x) {
return A(x);
}
void g() {
A r = f(10);
}
MSVC 实现这一点的方式是:
void f_impl(A* r, int x) {
new((void*)r) A(x); // construct the return value into r
}
void g_impl() {
A r = __uninitialized__;
f_impl(&r, 10);
}
在这里,您看到对复制构造函数的调用为零,并且没有临时对象。
如果你f
这样打电话:
void g() {
f(10);
}
然后编译器仍然需要在某处构造返回值,所以它创建了一个临时的:
void g_impl() {
A r = __uninitialized__;
f_impl(&r, 10);
r.~A(); // destruct temporary
}
什么时候调用复制构造函数?在执行f
时不知道f
会返回哪个'local'。例如这个:
A f(int x)
{
A r1;
A r2;
// ...do something complicated modifying both r1 and r2...
if(x)
return r1;
// ...do something complicated...
return r2;
}
被翻译成这样的东西:
void f_impl(A* r, int x)
{
A r1;
A r2;
// ...do something complicated modifying both r1 and r2...
if(x)
{
new((void*)r) A(r1); // copy construct r1
return;
}
// ...do something complicated...
new((void*)r) A(r2); // copy construct r2
}