2017-08-03 42 views
1
#include <iostream> 
#include <map> 
using namespace std; 

struct FooStruct 
{ 
    int a; 
    int b; 
}; 

int main() 
{ 
    map<int, FooStruct> fooMap; 
    fooMap.emplace<int, FooStruct>(0, {1, 2}); 
    return 0; 
} 

就防止臨時副本而言,上述是否正確使用emplace?在上述形式大於如何在使用emplace添加到std :: map時避免臨時副本?

fooMap.emplace(make_pair<int, FooStruct>(0, {1, 2})); 

更好或者是這些形式等同且二者避免造成FooStruct臨時副本?

+0

區別在於'make_pair'使用'pair'的移動構造函數語義,而另一種方式是調用模板的構造函數。 – Swift

+0

fooMap.emplace(std :: piecewise_construct,std :: forward_as_tuple(0),std :: forward_as_tuple(1,2));'? – max66

+0

@ max66:你是說你的表單比上面提到的兩個更好嗎?如果是這樣,你能解釋爲什麼是這樣嗎? – DigitalEye

回答

0

編輯:

在此線程討論的三種形式,即避免了不必要的拷貝之一是通過@ max66提出的形式。下面的代碼,並且其輸出捕獲動作這三種形式

#include <iostream> 
#include <map> 
using namespace std; 

struct FooStruct 
{ 
    FooStruct() 
    { 
     cout << "FooStruct Default Constructor" << endl; 
    } 
    FooStruct(const FooStruct& other) 
    { 
     this->a = other.a; 
     this->b = other.b; 
     cout << "FooStruct Copy Constructor" << endl; 
    } 
    FooStruct(int a, int b) 
    { 
     this->a = a; 
     this->b = b; 
     cout << "FooStruct Parametrized Constructor" << endl; 
    } 
    int a; 
    int b; 
}; 

輸出:

foo.emplace<int, FooStruct>(0, {1, 2}) 
FooStruct Parametrized Constructor 
FooStruct Copy Constructor 
fooMap.emplace(make_pair<int, FooStruct>(1, { 2, 3 })) 
FooStruct Parametrized Constructor 
FooStruct Copy Constructor 
FooStruct Copy Constructor 
fooMap.emplace(std::piecewise_construct, std::forward_as_tuple(2), std::forward_as_tuple(2, 4)) 
FooStruct Parametrized Constructor 

============

ORIGINAL(WRONG)

我很懶惰,在發佈問題前沒有深入挖掘。我現在看到所有這三種形式(第三種形式來自@ max66的評論)是相同的,因爲他們三個都避免了創建臨時副本FooStruct

#include <iostream> 
#include <map> 
using namespace std; 

struct FooStruct 
{ 
    FooStruct() { cout << "FooStruct Default Constructor" << endl; } 
    FooStruct(int a, int b) { this->a = a; this->b = b; cout << "FooStruct Parametrized Constructor" << endl; } 
    int a; 
    int b; 
}; 

int main() 
{ 
    map<int, FooStruct> fooMap; 
    fooMap.emplace<int, FooStruct>(0, {1, 2}); 
    fooMap.emplace(make_pair<int, FooStruct>(1, { 2, 3 })); 
    fooMap.emplace(std::piecewise_construct, std::forward_as_tuple(2), std::forward_as_tuple(2, 4)); 
    return 0; 
} 

上面的代碼(用Visual C++ 2015內置)產生以下輸出:

FooStruct Parametrized Constructor 
FooStruct Parametrized Constructor 
FooStruct Parametrized Constructor 

PS:我沒有驗證,在上述輸出的每一行對應於一個單一佈設呼叫以上

+1

我不同意這樣一個事實,即「所有這三種形式都是相同的,因爲它們三個都避免創建FooStruct的臨時副本」。第一種和第三種形式都是如此;在第二種情況下,據我所知,創建了一對'int' /'FooStruct'的臨時副本,用於在複製構造函數中構造映射對(移動構造函數,從C開始++ 11)。 – max66

+0

@ max66:你是對的。我忘了拷貝構造函數,顯然得出了錯誤的結論。所以,現在我們知道您的涉及forward_as_tuple的表單是最佳解決方案。我將編輯我的答案以反映這一發現。 – DigitalEye

1

如果定義了「正確性」爲簡便起見,您可能需要使用std::map::insert,而不是std::map::emplace這樣的:

fooMap.insert({0, {1, 2}}); 

隨着emplace你必須顯式地指定類型,比如在你的榜樣或FooStruct通過@ max66建議的情況下,定義構造函數明確:

fooMap.emplace(std::piecewise_construct, 
    std::forward_as_tuple(0), 
    std::forward_as_tuple(1, 2)); 

(這也沒啥簡潔)。

fooMap.insert({0, {1, 2}});不應該在創建的對象的數量計算從

fooMap.emplace(make_pair<int, FooStruct>(0, {1, 2})); 

是不同的,因爲它也使用了移動構造函數的std::pair作爲@Swift指出。

如果「正確」意味着「可編譯並且在運行時按預期工作」,那麼您的兩個示例都是正確的。

+0

好的,謝謝。我真正所追求的是一個直接在地圖內存中構建的FooStruct實例。 'fooMap.emplace(std :: piecewise_construct,std :: forward_as_tuple(0),std :: forward_as_tuple(1,2));'完成那個。其他形式,簡潔與否,涉及創建一個臨時FooStruct實例,這是我想避免的。 – DigitalEye

+0

您能否更新您的問題以反映您正在尋找構建的最小量的對象?此外,這種形式的'emplace'可能會產生很少的或沒有運行時性能的好處,因爲編譯器可以優化所有差異,您可能需要比較彙編。 –

相關問題