This页面说了一件奇怪的事: -
仅当您的程序没有将返回值复制到对象时才会创建临时值,并且给出的示例是
UDT Func1(); // Declare a function that returns a user-defined type.
...
Func1(); // Call Func1, but discard return value.
// A temporary object is created to store the return
// value
但如果我做了: -
UDT obj=Fuct1;
在我看来,它也会创建一个临时的: -
Func()
构造一个本地对象。接下来,在调用者的堆栈上复制构造此本地对象,使temporary object
用作obj的复制构造函数的参数。
我错了吗? 这与copy elision有关吗?
答案 0 :(得分:5)
您引用的页面描述了特定的行为 编译器。形式上:返回值始终是暂时的。在 将临时用作副本的参数的上下文 构造函数(对象被复制),标准给出了显式 授权编译器删除副本,“合并” 它正在初始化的命名变量临时。一切 你引用的句子是说这个特定的编译器总是如此 他的优化(和大多数其他编译器一样)。
答案 1 :(得分:3)
此页面是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
的本地时。例如。这样:
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
}
答案 2 :(得分:0)
返回值始终是暂时的。在第二种情况下,如果不能发生复制省略,那么临时(在C ++ 11中移动)的副本将被设为。