web-dev-qa-db-fra.com

Efficacité de C ++ 11 Push_back () avec std :: move contre emplace_back () pour les objets déjà construits

En C++ 11, emplace_back() est généralement préférable (en termes d'efficacité) à Push_back() car il permet la construction sur place, mais est-ce toujours le cas lors de l'utilisation de Push_back(std::move()) avec un objet déjà construit?

Par exemple, emplace_back() est-il toujours préféré dans les cas suivants?

std::string mystring("hello world");
std::vector<std::string> myvector;

myvector.emplace_back(mystring);
myvector.Push_back(std::move(mystring));
// (of course assuming we don't care about using the value of mystring after)

En outre, l'exemple ci-dessus présente-t-il un avantage à:

myvector.emplace_back(std::move(mystring));

ou est-ce que le déménagement ici est entièrement redondant ou n'a pas d'effet?

76
Riot

Voyons ce que font les différents appels que vous avez fournis:

  1. emplace_back(mystring): il s'agit d'une construction sur place du nouvel élément avec l'argument que vous avez fourni. Puisque vous avez fourni une lvalue, cette construction sur place est en fait une copie de construction, c’est-à-dire qu’elle revient à appeler Push_back(mystring)

  2. Push_back(std::move(mystring)): Ceci appelle le move-insertion, qui dans le cas de std :: string est une construction move-in.

  3. emplace_back(std::move(mystring)): Il s'agit à nouveau d'une construction sur place avec les arguments que vous avez fournis. Comme cet argument est une valeur rvalue, il appelle le constructeur de mouvements de std::string, C’est-à-dire qu’il s’agit d’une construction de mouvements sur place comme dans 2.

En d'autres termes, si appelé avec un argument de type T, que ce soit une valeur ou une valeur, emplace_back Et Push_back Sont équivalents.

Cependant, pour tout autre argument, emplace_back Remporte la course, par exemple avec un char const* Dans un vector<string>:

  1. emplace_back("foo") appelle string::string(char const*) pour la construction sur place.

  2. Push_back("foo") doit d'abord appeler string::string(char const*) pour la conversion implicite nécessaire pour correspondre à la signature de la fonction, puis une insertion-déplacement comme dans le cas 2. ci-dessus. Par conséquent, cela équivaut à Push_back(string("foo"))

104
Arne Mertz

Emplace_back obtient une liste de références rvalue et tente de construire un élément conteneur directement à la place. Vous pouvez appeler emplace_back avec tous les types pris en charge par les constructeurs d'éléments de conteneur. Lorsque vous appelez emplace_back pour les paramètres qui ne sont pas des références rvalue, il revient aux références normales et au moins le constructeur de copie est appelé lorsque le paramètre et les éléments de conteneur sont du même type. Dans votre cas, 'myvector.emplace_back (mystring)' doit faire une copie de la chaîne car le compilateur ne peut pas savoir que le paramètre myvector est déplaçable. Donc insérez std :: move ce qui vous donne l’avantage désiré. Push_back devrait fonctionner aussi bien que emplace_back pour les éléments déjà construits.

1
Tunichtgut