2012-01-27 90 views
3

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的拷貝構造函數的參數。

我錯了嗎?
這是否與複製elision有關?

回答

5

頁你舉的這一個特定的 編譯器的行爲的描述。形式上:返回值總是暫時的。在 上下文,其中該臨時被用作複製 構造(該對象被複制)的參數,該標準給出了明確的 授權編譯器的Elid副本,「合併」 臨時與命名的變量被初始化。你引用的所有 句子都是說這個特定的編譯器總是會優化它(與大多數其他編譯器一樣)。

0

返回值總是一個臨時值。在第二種情況下,如果 copy elision不能發生,則將該臨時副本(在C++ 11中移動)製作爲

+0

如果一個函數返回一個引用,那是否也被認爲是臨時的? – 2012-01-27 05:45:32

+0

@SethCarnegie:不,因爲引用不是對象(儘管我不能想到這可能很重要的情況)。 – Mankarse 2012-01-27 07:43:47

+0

當您嘗試將臨時對象綁定到從函數返回的引用時,它會發生排序。 (不要這樣做!)。 – MSalters 2012-01-27 08:42:41

3

此頁面是Microsoft特定的。確實,標準允許在函數返回期間對複製構造函數執行兩次,一次或零次調用(這稱爲複製elision)。事實上,一個電話總是足夠的。

假設你寫:

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 
}