push_back o emplace_back con std::make_unique

1 minuto de lectura

Avatar de usuario de NHDaly
NHDaly

Según las respuestas a estas preguntas aquí, sé que ciertamente se prefiere usar c ++ 14 std::make_unique que a emplace_back(new X) directamente.

Dicho esto, es preferible llamar

my_vector.push_back(std::make_unique<Foo>("constructor", "args"));

o

my_vector.emplace_back(std::make_unique<Foo>("constructor", "args"));

Es decir, ¿debería usar push_back o emplace_back al agregar un std::unique_ptr construido a partir de std::make_unique?

==== EDITAR ====

¿y por qué? c:

  • Con un argumento real del tipo de elemento del vector, push_back y emplace_back necesariamente hacer lo mismo.

    – Saludos y hth. – alf

    17 de marzo de 2015 a las 0:21

  • Relacionado: htmlpreview.github.io/?https://github.com/HowardHinnant/papers/…

    – mojar

    17 de marzo de 2015 a las 0:21

  • @Praetorian, gracias.

    – NHDaly

    17 de marzo de 2015 a las 0:24

  • Si tiene un eliminador personalizado en su unique_ptrentonces las cosas pueden cambiar.

    – Yakk – Adam Nevraumont

    17 de marzo de 2015 a las 0:59

  • Con respecto al enlace de @dyp, ejecuté ese código en VS2022 e insertar y colocar fueron idénticos en cada caso.

    – Tomás

    8 dic 2022 a las 18:32

Avatar de usuario de Praetorian
Pretoriano

No hace ninguna diferencia en lo que se refiere a la construcción del nuevo objeto; ya tienes un unique_ptr<Foo> prvalue (el resultado de la llamada a make_unique) por lo tanto push_back y emplace_back llamará al unique_ptr mueva el constructor al construir el elemento que se agregará al vector.

Si su caso de uso implica acceder al elemento recién construido después de la inserción, entonces emplace_back es más conveniente desde C++17 porque devuelve una referencia al elemento. Entonces, en lugar de

my_vector.push_back(std::make_unique<Foo>("constructor", "args"));
my_vector.back().do_stuff();

puedes escribir

my_vector.emplace_back(std::make_unique<Foo>("constructor", "args")).do_stuff();

  • Si de acuerdo, por eso pregunto. 🙂

    – NHDaly

    17 de marzo de 2015 a las 1:15

  • En realidad, hay una diferencia… emplace_back() devuelve una referencia al elemento añadido, mientras que push_back() devuelve nula. emplace_back(std::make_unique<>()) por lo tanto, es útil en contextos en los que necesita usar el objeto después de haberlo agregado.

    – jb

    19/09/2018 a las 18:40

  • @JamieBullock Bueno, no hubo diferencia cuando respondí la pregunta hace 3 años. Se actualizó la respuesta para incluir el cambio de C++ 17 al tipo de devolución. Gracias.

    – Pretoriano

    19/09/2018 a las 19:45

Yakk - Avatar de usuario de Adam Nevraumont
Yakk – Adam Nevraumont

Claramente

template<class T, class A, class...Args>
void push_unique( std::vector<std::unique_ptr<T>,A>& v, Args&&...args ) {
  v.push_back( std::make_unique<T>(std::forward<Args>(args)...) );
}

es la mejor opción:

push_unique(my_vector,"constructor", "args");

lamentablemente, esta es la notación de prefijo: (operador, contenedor, argumentos…) vs infijo (argumentos de operador de contenedor…).

Si tan solo hubiera una manera de hacerlo infijo, como métodos de extensión o operadores con nombre.

Porque eso sería genial.

¿Ha sido útil esta solución?