2017-09-05 123 views
15

在C++ 1z中,std::mapstd::unordered_map有一個新的成員函數模板:try_emplace()。這個新此外,在n4279提出,行爲類似於emplace(),但具有以下優點:是否有任何理由在C++ 1z中使用std :: map :: emplace()而不是try_emplace()?

  • try_emplace()不從右值參數的移動,如果插入不會發生。在處理值爲僅移動類型的地圖時,這非常有用,例如std::unique_ptr
  • try_emplace()分別對待mapped_type的密鑰和參數,這使得它比根據value_type(即std::pair)表示的通用增變器更直觀。

鑑於上述優點,編寫C++ 1Z-唯一代碼時,你會永遠使用來自C++ 11,而不是try_emplace()emplace()從C++ 1Z?

+0

'emplace'可能會快幾個週期,因爲它不檢查插入是否發生,但這不是一個真正的好理由。 –

+0

與try_emplace增加的優勢,我總是喜歡這個在emplace –

+2

@HenriMenke:''emplace()''確實檢查重複,*建立''value_type''後*。如果找到重複項,效率會低得多,因爲它需要執行分配(並且在重複的情況下取消分配)。 –

回答

13

try_emplace確實可以代替emplace的大多數用途,但是如果您有一個不可複製和不可移動密鑰類型的不尋常用例maptry_emplace將不起作用,因爲它複製或移動密鑰。在這種情況下,您必須使用emplacestd::pairpiecewise construction constructor以避免複製和移動。

即使您的鑰匙類型是可複製和/或可移動的,分段結構是避免複製或移動構造鑰匙的唯一方法,因此可能會出現您比try_emplace更喜歡的情況。

4

我總是比較喜歡try_emplace而不是emplace。一個關鍵的區別是,如果密鑰已經存在,則try_emplace不會構造與該密鑰相關聯的對象。這將提高性能,以防該類型的對象創建成本高。

例如,下面的代碼(https://github.com/PacktPublishing/Cpp17-STL-Cookbook/blob/master/Chapter02/efficient_insert_or_reassign_to_map.cpp

#include <iostream> 
#include <functional> 
#include <list> 
#include <map> 

using namespace std; 

struct billionaire { 
    string name; 
    double dollars; 
    string country; 
}; 

int main() 
{ 
    list<billionaire> billionaires { 
     {"Bill Gates", 86.0, "USA"}, 
     {"Warren Buffet", 75.6, "USA"}, 
     {"Jeff Bezos", 72.8, "USA"}, 
     {"Amancio Ortega", 71.3, "Spain"}, 
     {"Mark Zuckerberg", 56.0, "USA"}, 
     {"Carlos Slim", 54.5, "Mexico"}, 
     // ... 
     {"Bernard Arnault", 41.5, "France"}, 
     // ... 
     {"Liliane Bettencourt", 39.5, "France"}, 
     // ... 
     {"Wang Jianlin", 31.3, "China"}, 
     {"Li Ka-shing", 31.2, "Hong Kong"} 
     // ... 
    }; 

    map<string, pair<const billionaire, size_t>> m; 

    for (const auto &b : billionaires) { 
     auto [iterator, success] = m.try_emplace(b.country, b, 1); 

     if (!success) { 
      iterator->second.second += 1; 
     } 
    } 


    for (const auto & [key, value] : m) { 
     const auto &[b, count] = value; 

     cout << b.country << " : " << count << " billionaires. Richest is " 
     << b.name << " with " << b.dollars << " B$\n"; 
    } 
} 

對於上述代碼

m.try_emplace(b.country, b, 1); 

如果不成功插入對將不會構成這增加了性能

7

try_emplace也不支持異構查找 - 它不能,因爲它需要密鑰。

假設我們有和std::string_viewsv。我想要做相當於++counts[std::string(sv)];,但我不想創建臨時std::string,這只是浪費,特別是如果字符串已經存在於地圖中。 try_emplace不能幫助你。相反,你會做類似

if(auto lb = counts.lower_bound(sv); lb != counts.end() && lb->first == sv) { 
    ++lb->second; 
} 
else { 
    counts.emplace_hint(lb, sv, 1); 
} 
相關問題