2012-11-27 59 views
0

多少份發生/對象存在於以下,假設正常的編譯器優化已啓用:推臨時分解到C++

std::vector<MyClass> v; 
v.push_back(MyClass()); 

如果不是正好1個對象的創建和0複製,我能(包括MyClass中的更改)以實現這一目標,因爲在我看來,這確實是必要的嗎?

+4

你確定'v.push_back(v());'? – billz

+0

「假定正常的編譯器優化已啓用」?沒有像「正常編譯器優化」這樣的事情 - 取決於編譯器,使用的編譯器選項等。 –

+0

我想這更像v.push_back(MyClass()); –

回答

4

如果MyClass的構造函數有副作用,那麼在C++ 03中不允許複製副本。這是因爲作爲副本源的臨時對象已被綁定到引用(參數push_back)。

如果MyClass的複製構造函數沒有副作用,那麼允許編譯器在「as-if」規則下優化它。我認爲唯一明智的方法來確定它是否真正採用「正常優化」的方式來完成這項工作是檢查發出的代碼。不同的人有不同的想法是正常的,並且給定的編譯器可能對MyClass的細節敏感。我的猜測是,這相當於編譯器(或鏈接器)是否將所有內容都包含在內。如果這樣做,那麼它可能會優化,如果它不,那麼它不會。所以即使構造函數代碼的大小可能是相關的,但不要介意它的作用。

所以我認爲你可以做的主要事情是確保MyClass的默認和複製構造函數都沒有副作用並且可以內聯。如果它們不可用,那麼編譯器當然會認爲它們可能有副作用並且會執行副本。如果鏈接時間優化對你來說是一個正常的編譯器選項,那麼你不需要做太多的工作就可以使它們可用。否則,如果它們是用戶定義的,那麼在定義MyClass的頭文件中執行它。你可能能夠避開帶有某種副作用的默認構造函數:如果效果不依賴於臨時變量的地址與向量元素的地址不同,那麼「as-if」仍然適用。

在C++ 11中,你有一個舉動(如果它有副作用,它也不能被消除),但是你可以使用v.emplace_back()來避免這種情況。如果它的移動構造函數有MyClass,那麼它會調用MyClass的移動構造函數,否則複製構造函數以及上面關於「如果」的所有內容適用於移動。 emplace_back()調用no-args構造函數來構造向量元素(或者如果您將參數傳遞給emplace_back,那麼任何構造函數都會匹配那些args),我認爲這正是您想要的。

1

你的意思是:

std::vector<MyClass> v; 
v.push_back(MyClass()); 

無。臨時會導致調用push_back的移動版本。即使移動建設將很可能會被取消。

+2

如果編譯器不是C++ 11編譯器? –

+0

沒有什麼?我假定你的意思是沒有副本,只有一個創作? – baruch

+0

你問'有多少份'? –

1

如果您有C++ 11編譯器,則可以使用emplace_back在向量末尾構建元素,並且需要零拷貝。

0

在C++ 03中,您將擁有一個構造和一個副本,並且還會臨時銷燬。

如果你的編譯器支持C++ 11並且MyClass定義了一個移動構造器,那麼你有一個構造和一個移動。

正如Timbo所提到的那樣,您也可以使用emplace_back來避免移動,該對象正在原地構建。