我可以通過用emplace_back
替換std::vector::push_back
並用C++ 11編譯器編譯它來打破有效的C++ 03程序嗎?從閱讀emplace_back
參考我收集它不應該發生,但我承認我沒有完全得到右值引用。是否有任何情況下用emplace_back替換push_back是不正確的?
回答
我構成,即實際失效時push_back
由emplace_back
取代編譯一個短例如:
#include <vector>
struct S {
S(double) {}
private:
explicit S(int) {}
};
int main() {
std::vector<S>().push_back(0); // OK
std::vector<S>().emplace_back(0); // error!
}
到push_back
的呼叫需要它的參數從0
int
類型轉換爲鍵入S
。由於這是隱式轉換,因此不考慮顯式構造函數S::S(int)
,並調用S::S(double)
。另一方面,emplace_back
執行直接初始化,因此都考慮S::S(double)
和S::S(int)
。後者是一個更好的匹配,但它是private
,所以該程序是格式不正確。
如果您在向量中保存的對象的拷貝構造函數中沒有任何瘋狂的副作用,那麼不會。
emplace_back
被引入來優化不必要的複製和移動。
另請注意,其中的一些優化也適用於'push_back'。 –
是的,但編譯器*必須確定*構造函數是微不足道的,這樣做不會改變整體結果 – Kissiel
我正在考慮通過移動捕獲,push_back現在移動感知。不知道你在想我的意思。 –
是的,您可以更改行爲(不僅僅是避免複製構造函數調用),因爲emplace_back
只能看到不完全轉發的參數。
#include <iostream>
#include <vector>
using namespace std;
struct Arg { Arg(int) {} };
struct S
{
S(Arg) { cout << "S(int)" << endl; }
S(void*) { cout << "S(void*)" << endl; }
};
auto main()
-> int
{
vector<S>().ADD(0);
}
實施例構建:
[H:\dev\test\0011] > g++ foo.cpp -D ADD=emplace_back && a S(int) [H:\dev\test\0011] > g++ foo.cpp -D ADD=push_back && a S(void*) [H:\dev\test\0011] > _
補遺:如在his answer指出由Brian畢,另一個差,可導致不同的行爲是一個push_back
呼叫涉及的隱式轉換到T
,無視explicit
構造函數和轉換運算符,而emplace_back
使用直接初始化,它做c也可以嘗試explicit
構造函數和轉換操作符。
你能否更詳細地解釋這是如何工作的?我試圖弄清楚自己,但我真的很感興趣。 – Brian
@BrianBi:轉換序列中不能有多個用戶定義的轉換。所以'null指針常量' - >'void *' - >'S'是唯一可用的'push_back'轉換。使用'emplace_back','0'是一個空指針常量的事實丟失了,因爲模板參數包無法捕獲它,它只是捕獲它是'int'(因此「不完全轉發」)。此外,在一個序列中不需要兩個用戶定義的轉換,因爲我們明確構造了一個「S」。所以'Arg'構造函數被選擇爲'S',並帶有隱式轉換'int' - >'Arg'。 –
@SteveJessop:謝謝,因爲事實證明我沒有100%的理解我自己的示例代碼,直到我閱讀你對Brian的回覆。 :-) –
在異常情況下,emplace
版本不會在所有處創建所需類型的對象。這可能會導致錯誤。
請看下面的例子,爲了簡單起見,使用std::vector
(假設uptr
行爲就像std::unique_ptr
,除了構造函數不明確):
std::vector<uptr<T>> vec;
vec.push_back(new T());
這是異常安全。創建一個臨時的uptr<T>
傳遞到push_back
,它被移動到矢量中。如果向量重新分配失敗,則分配的T
仍由智能指針所擁有,該智能指針正確刪除它。
對比:
std::vector<uptr<T>> vec;
vec.emplace_back(new T());
emplace_back
不允許創建一個臨時對象。 ptr
將在矢量中就地創建一次。如果重新分配失敗,就地創建沒有位置,並且不會創建智能指針。 T
將被泄露。
當然,最好的辦法是:
std::vector<std::unique_ptr<T>> vec;
vec.push_back(make_unique<T>());
這相當於第一,但讓智能指針創建明確的。
- 1. 是否有任何情況下不應使用任務?
- 2. Emplace_back而不是push_back對stl容器?
- 3. 是否有任何情況下圖像可能無法正確縮放?
- 4. 是否有任何情況下DateTimeOffset可能不可靠?
- 5. 是否有任何情況下Application.Exit()不會引發FormClosing事件?
- 6. 是否有任何情況下finally塊不會被執行?
- 7. push_back vs emplace_back
- 8. PropType不是在任何情況下
- 9. 是否有任何替代實施100-1000「if ... else」情況
- 10. 我是否在這種情況下正確使用ForeignKey?
- 11. 這是否正確使用$。在這種情況下推出?
- 12. WPF是否完全替代了Winforms,或者是否有任何情況下可以使用WPF的winforms
- 13. 是否有任何情況下使用探查器不應該使用?
- 14. AUTO_INCREMENT在我的情況下是否正確實施?
- 15. 在postgres中的替換函數是否有例外情況
- 16. 是否有任何情況下您不能使用回溯算法方法?
- 17. 在這種情況下,CoreData遷移是否正確?
- 18. 在這種情況下,OAuth和OpenID是否正確?
- 19. 在這種情況下plist文件是否正確選擇?
- 20. 是否可以在沒有選擇器的情況下替換文本?
- 21. 是否有任何情況下表單的激活事件不會引發?
- 22. 是否有32位變量無法正確對齊的情況
- 23. 是否有任何替代方法可以在不使用POM.xml的情況下獲得依賴關係?
- 24. YQL是否不可靠地返回正確的數據 - 任何替換?
- 25. 玉觀點並不是在我的情況下正確呈現
- 26. 在所有情況下,Flink garauntee任務是否容錯?
- 27. 是否有任何正則表達式替換?
- 28. 正則表達式如何在不替換任何其他數字的情況下替換$ value
- 29. 查找和MySQL的替換 - 精確匹配情況下,只有
- 30. 在不刪除的情況下更新堆棧信息是否正確?
+1我沒有想到這一點。整齊。 –
的確,聰明。當我第一次看到這個問題時,我想,「好吧,'emplace_back'可以調用顯式構造函數」。然後我愚蠢地想,「但是從'emplace_back'到'push_back'時,這是一個突破性的改變,而不是相反。你可以在'push_back'不是''struct s {S(double){} explicit S(float){}};''的情況下'emplace_back'調用變得模糊不清:當然,這是一個*糟糕的*一組構造函數給'S'。 –
那麼這是否意味着只要能夠成功編譯代碼,就不用擔心轉移到emplace_back? – BrandonSun