2011-08-09 9 views
40

En primer lugar, soy consciente de this question, pero no creo que pregunte lo mismo.¿Por qué no se pudo sobrecargar push_back para hacer el trabajo de emplace_back?

Sé lo hace std::vector<T>::emplace_back - y entiendo por qué lo usaría más push_back(). Utiliza plantillas variadic que me permiten reenviar múltiples argumentos al constructor de un nuevo elemento.

Pero lo que no entiendo es por qué el comité estándar de C++ decidió que había una necesidad de una nueva función de miembro. ¿Por qué no podrían simplemente extender la funcionalidad de push_back()? Por lo que yo puedo ver, push_back podría estar sobrecargado en C++ 11 a ser:

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

Esto no rompería la compatibilidad hacia atrás, mientras que le permite pasar N argumentos, incluidos los argumentos que pueden invocar un rvalue normal o copia constructor De hecho, el compilador de C++ 11 implementación de push_back() simplemente llama emplace_back todos modos:

void push_back(value_type&& __x) 
    { 
    emplace_back(std::move(__x)); 
    } 

Por lo tanto, la forma en que lo veo, no hay necesidad de emplace_back(). Todo lo que necesitaban agregar era una sobrecarga para push_back() que acepta argumentos variados y reenvía los argumentos al constructor del elemento.

¿Me equivoco aquí? ¿Hay alguna razón por la cual se necesita una función completamente nueva aquí?

+1

esto parece similar: http://stackoverflow.com/questions/4303513/push-back-vs-emplace-back – moka

+7

Buena pregunta. @moka conoce la diferencia entre lo que hacen las dos funciones. Incluso se vinculó a esa pregunta en particular. –

+0

Tienen diferentes significados, todo se explica en la pregunta que mencionaste que leíste. Compare 'v.emplace_back (123)' y 'v.push_back (123)' por ejemplo para 'vector v;' con conversión implícita de 'int'. –

Respuesta

38

Si T tiene un constructor de conversión explícita, existe un comportamiento diferente entre emplace_back y push_back.

struct X 
{ 
    int val; 
    X() :val() {} 
    explicit X(int v) :val(v) {} 
}; 

int main() 
{ 
    std::vector<X> v; 
    v.push_back(123); // this fails 
    v.emplace_back(123); // this is okay 
} 

Hacer el cambio que sugieres que significaría que habría push_back legal en esa instancia, y supongo que no estaba comportamiento deseado. No sé si esta es la razón, pero es lo único que se me ocurre.

+7

Es especialmente útil cuando se manejan contenedores de 'unique_ptr's, ya que' v.emplace_back (new foo) 'es mucho más simple que' v.push_back (std :: unique_ptr (new foo)) '. Pero uno debería ser capaz de * solicitar explícitamente * la conversión en este caso. –

+0

@AlexandreC .: En realidad, 'emplace_back (new foo)' no es a prueba de excepciones, por lo que es una acción incorrecta. – Mehrdad

+0

@Mehrdad ¿te refieres a que la posible asignación puede fallar? Diablos, eso es verdad ... –

1

Aquí hay otro ejemplo.

Honestamente, los dos son semánticamente tan diferente, que su comportamiento similar debería ser considerada como una mera coincidencia (debido al hecho de que C++ tiene "constructores de copia" con una sintaxis particular).

realmente debería no uso emplace_back a menos que desee en el lugar de la construcción- semántica.
Es raro que necesites tal cosa. En general, push_back es lo que realmente quiere, semánticamente.

#include <vector> 

struct X { X(struct Y const &); }; 
struct Y { Y(int const &); operator X(); }; 

int main() 
{ 
    std::vector<X> v; 
    v. push_back(Y(123)); // Calls Y::operator X() and Y::Y(int const &) 
    v.emplace_back(Y(123)); // Calls X::X(Y const &) and Y::Y(int const &) 
} 
Cuestiones relacionadas