2011-09-30 53 views
4

複製elision方法的標準定義: 在C++計算機編程中,複製elision是指消除不必要的對象複製的編譯器優化技術。 讓我們考慮下面的代碼複製elision方法

#include <cstdlib> 
#include <iostream> 
using namespace std; 
int n=0; 
struct C 
{ 
C (int) {} 
C(const C&) {++n;}  



     }; 
int main(int argc, char *argv[]) 
{ 
    C c1(42); 
    C c2=42; 




return n; 
} 

這條線「返回N」將返回0或1,這取決於複製是否被省略。

也考慮這個代碼

#include <iostream> 

struct C { 
    C() {} 
    C(const C&) { std::cout << "Hello World!\n"; } 
}; 

void f() { 
    C c; 
    throw c; // copying the named object c into the exception object. 
}   // It is unclear whether this copy may be elided. 

int main() { 
    try { 
    f(); 
    } 
    catch(C c) { 
} 
} 

它說, //複製異常對象到臨時在異常聲明。 //此副本是否可能被取消也不清楚。 所以我的問題是實現這種優化方法有多麼有用,如果有時結果是不確定的?一般來說它的使用頻率如何?

+0

在第一個例子中甚至沒有副本。對於第二個示例:http://stackoverflow.com/q/7401521/46642 –

+3

@ R.MartinhoFernandes:在這個問題的第二個例子(而不是你的鏈接問題)中,與NRVO發生的警告相同:從'如果編譯器可以保證在構造對象'c'時拋出異常,那麼只有在異常的內部存儲器才能被刪除。即使在那裏,根據我的理解,用戶所具有的問題是標準沒有強制規定這種行爲,這意味着您不能依賴複製構造函數的副作用 - 這是標準明確指出的 –

回答

8

重要的是,標準明確允許這一點,這意味着你不能假定複製構造函數的副作用將被執行,因爲副本可能會被忽略。該標準要求執行複製構造函數具有複製構造函數語義,也就是說,具有在您的域中與原始對象在語義上等同的第二個對象的生成的全部目的。如果你的程序符合那個,那麼優化不會影響程序。另一方面,這是唯一的情況,我可以認爲這個標準允許來自同一個程序的不同可見結果取決於編譯器的作用,但是你已經被告知你不應該在你的拷貝構造函數中有副作用(或者說,你不能依賴於執行拷貝的確切數量)。

至於是否值得,是的。在許多情況下,副本非常昂貴(我故意忽略C++ 11中的移動構造函數)。考慮一個返回vector<int>的函數,如果不復制副本,則需要另一個動態分配,複製所有向量內容,然後釋放原始內存塊,這三個操作都可能很昂貴。

或者,您可以強制用戶更改其代碼以創建一個空對象並通過引用傳遞它,但這會使代碼難以閱讀。