返回值总是暂时的吗?

时间:2012-01-27 05:33:29

标签: c++ temporary-objects

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有关吗?

3 个答案:

答案 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中移动)的副本将被设为