990

push_backとの違いについて少し混乱していemplace_backます。

void emplace_back(Type&& _Val);
void push_back(const Type& _Val);
void push_back(Type&& _Val);

右辺値参照をとる過負荷があるpush_backので、目的がどうなるかよくわかりませんemplace_backか?

4

7 に答える 7

708

訪問者が言ったことに加えて:

ご指摘のとおり、MSCV10が提供する機能void emplace_back(Type&& _Val)は、厳密にと同等であるため、非準拠で冗長ですpush_back(Type&& _Val)

しかし、の実際のC++0x形式emplace_backは本当に便利ですvoid emplace_back(Args&&...)

引数を取る代わりにvalue_type、引数の可変個引数リストを取ります。つまり、引数を完全に転送し、一時的なものをまったく使わずにオブジェクトをコンテナに直接構築できるようになりました。

RVOとmoveセマンティックがテーブルにどれほど巧妙さをもたらしても、push_backが不要なコピー(または移動)を作成する可能性が高い複雑なケースがまだあるため、これは便利です。たとえば、の従来insert()の機能ではstd::map、一時的なものを作成する必要があります。一時的なものは、にコピーされ、std::pair<Key, Value>次にマップにコピーされます。

std::map<int, Complicated> m;
int anInt = 4;
double aDouble = 5.0;
std::string aString = "C++";

// cross your finger so that the optimizer is really good
m.insert(std::make_pair(4, Complicated(anInt, aDouble, aString))); 

// should be easier for the optimizer
m.emplace(4, anInt, aDouble, aString);

では、なぜ彼らはMSVCに正しいバージョンのemplace_backを実装しなかったのでしょうか。実際、それは私を少し前に悩ませたので、私はVisualC++ブログで同じ質問をしました。これは、MicrosoftのVisualC++標準ライブラリ実装の公式メンテナであるStephanTLavavejからの回答です。

Q:ベータ2エンプレース関数は、現在、ある種のプレースホルダーにすぎませんか?

A:ご存知かもしれませんが、可変個引数テンプレートはVC10には実装されていません。make_shared<T>()、タプル、およびの新しいもののプリプロセッサ機構を使用してそれらをシミュレートします <functional>。このプリプロセッサ機構は、使用と保守が比較的困難です。また、サブヘッダーを繰り返し含める必要があるため、コンパイル速度に大きく影響します。時間の制約とコンパイル速度の懸念の組み合わせにより、emplace関数で可変個引数テンプレートをシミュレートしていません。

可変個引数テンプレートがコンパイラーに実装されると、emplace関数を含むライブラリーでそれらを利用することが期待できます。私たちは適合性を非常に真剣に受け止めていますが、残念ながら、すべてを一度に行うことはできません。

それは理解できる決断です。プリプロセッサの恐ろしいトリックで可変個引数テンプレートをエミュレートしようとしたことのある人なら誰でも、このようなものがいかに嫌なものになるかを知っています。

于 2010-11-29T18:00:28.900 に答える
238

emplace_backタイプの引数を取るべきではありませんがvector::value_type、代わりに、追加されたアイテムのコンストラクターに転送される可変個引数を取ります。

template <class... Args> void emplace_back(Args&&... args); 

value_typeコピーコンストラクタに転送されるaを渡すことができます。

引数を転送するため、右辺値がない場合でも、コンテナは移動されたコピーではなく、「コピーされた」コピーを格納することを意味します。

 std::vector<std::string> vec;
 vec.emplace_back(std::string("Hello")); // moves
 std::string s;
 vec.emplace_back(s); //copies

しかし、上記は何をするかと同じでなければなりpush_backません。おそらく、次のようなユースケースを対象としています。

 std::vector<std::pair<std::string, std::string> > vec;
 vec.emplace_back(std::string("Hello"), std::string("world")); 
 // should end up invoking this constructor:
 //template<class U, class V> pair(U&& x, V&& y);
 //without making any copies of the strings
于 2010-11-29T12:47:56.663 に答える
125

の最適化はemplace_back、次の例で示すことができます。

emplace_backコンストラクターA (int x_arg)が呼び出されます。そして、for push_back A (int x_arg)が最初にmove A (A &&rhs)呼び出され、後で呼び出されます。

もちろん、コンストラクターはとしてマークする必要がありますexplicitが、現在の例では、明示性を削除することをお勧めします。

#include <iostream>
#include <vector>
class A
{
public:
  A (int x_arg) : x (x_arg) { std::cout << "A (x_arg)\n"; }
  A () { x = 0; std::cout << "A ()\n"; }
  A (const A &rhs) noexcept { x = rhs.x; std::cout << "A (A &)\n"; }
  A (A &&rhs) noexcept { x = rhs.x; std::cout << "A (A &&)\n"; }

private:
  int x;
};

int main ()
{
  {
    std::vector<A> a;
    std::cout << "call emplace_back:\n";
    a.emplace_back (0);
  }
  {
    std::vector<A> a;
    std::cout << "call push_back:\n";
    a.push_back (1);
  }
  return 0;
}

出力:

call emplace_back:
A (x_arg)

call push_back:
A (x_arg)
A (A &&)
于 2015-10-27T16:42:56.627 に答える
18

リストのもう1つの例:

// constructs the elements in place.                                                
emplace_back("element");

// creates a new object and then copies (or moves) that object.
push_back(ExplicitDataType{"element"});
于 2017-12-28T10:08:56.923 に答える
14

特定のユースケースemplace_back:一時オブジェクトを作成してコンテナにプッシュする必要がある場合は、のemplace_back代わりにを使用しpush_backます。コンテナ内のインプレースでオブジェクトを作成します。

ノート:

  1. push_back上記の場合、一時オブジェクトを作成し、それをコンテナに移動します。ただし、に使用されるインプレース構築はemplace_back、オブジェクトを構築してから移動するよりもパフォーマンスが高くなります(通常はコピーが必要です)。
  2. 一般的に、すべての場合のemplace_back代わりに、多くの問題なく使用できます。push_back例外を参照)
于 2019-12-13T23:14:41.540 に答える
10

push_backとemplace_backの優れたコードをここに示します。

http://en.cppreference.com/w/cpp/container/vector/emplace_back

移動操作は、emplace_backではなくpush_backで確認できます。

于 2018-02-27T14:26:20.337 に答える
9

emplace_back準拠する実装はvector<Object>::value_type、ベクトルに追加されると、引数をコンストラクターに転送します。Visual Studioは可変個引数テンプレートをサポートしていなかったことを思い出しますが、可変個引数テンプレートはVisual Studio 2013 RCでサポートされるため、準拠する署名が追加されると思います。

を使用emplace_backすると、引数をコンストラクターに直接転送する場合、厳密に言えば、関数vector<Object>::value_typeに対して移動可能またはコピー可能である型は必要ありません。emplace_backこの場合、 成長するにはコピー可能または移動可能なタイプが必要になるvector<NonCopyableNonMovableObject>ため、これは役に立ちません。vector<Object>::value_type

ただし、これはに役立つ可能性があることに注意std::map<Key, NonCopyableNonMovableObject>してください。マップにエントリを割り当てると、とは異なり、移動またはコピーする必要がなくなります。つまり、コピーもコピーもできないマップされたタイプでも効果的にvector使用できます。std::map可動。

于 2013-09-24T04:39:05.270 に答える