2017-09-05 4 views
15

C++ 1zでは、std::mapstd::unordered_mapは、新しいメンバ関数テンプレート:try_emplace()を取得しました。 n4279で提案されたこの新しい追加は、emplace()と同様に動作しますが、次のような利点があります:挿入が起こらない場合C++ 1zでtry_emplace()の代わりにstd :: map :: emplace()を使用する理由はありますか?

  • try_emplace()が右辺値引数から移動しません。これは、値がstd::unique_ptrなどの移動専用タイプのマップを操作する場合に便利です。
  • try_emplace()は、mapped_typeのキーと引数を個別に扱います。value_type(つまりstd::pair)で表される汎用ミューテータよりもやや直感的です。上記の利点を考えると

C++ 1Z専用のコードを書くとき、あなたはC++ 1ZからC++ 11の代わりに、try_emplace()からemplace()を使うのでしょうか?

+0

'emplace'は挿入が起こっているかどうかをチェックしないので速くなるかもしれませんが、それは本当に良い理由ではありません。 –

+0

がtry_emplaceの利点を追加しています。私はいつもこれをemplaceよりも好きです。 –

+2

@HenriMenke: '' emplace() ''は、 '' value_type''の後に*重複をチェックします。重複が見つかった場合は、割り当てを実行する必要があり(重複の場合には割り当てを解除する必要があるため)、はるかに効率的ではありません。 –

答えて

13

try_emplace実際にはほとんどの用途をemplaceに置き換えることができますが、mapのコピー可能で不動のキータイプの珍しい使用例がある場合、try_emplaceはキーをコピーまたは移動するため動作しません。その場合は、emplacestd::pairpiecewise construction constructorを使用して、コピーと移動を避ける必要があります。

あなたのキータイプがコピー可能かつ/または移動可能であっても、コピーを作成または移動することを回避する唯一の方法は、ピース単位の構造であるため、try_emplaceを好む場合があります。

4

私は常にemplaceよりもtry_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); 
} 
関連する問題