La mejor manera de añadir vector a vector


std::vector<int> a;
std::vector<int> b;
std::vector<int> c;

Me gustaría concatenar estos tres vectores anexando b y c's elementos a a. ¿Cuál es la mejor manera de hacer esto, y por qué?


1) Usando vector::insert:

a.reserve(a.size() + b.size() + c.size());
a.insert(a.end(), b.begin(), b.end());
a.insert(a.end(), c.begin(), c.end());
b.clear();
c.clear();

2) Usando std::copy:

a.reserve(a.size() + b.size() + c.size());
std::copy(b.begin(), b.end(), std::inserter(a, a.end()));
std::copy(c.begin(), c.end(), std::inserter(a, a.end()));
b.clear();
c.clear();

3) Usando std::move (de C++11):

a.reserve(a.size() + b.size() + c.size());
std::move(b.begin(), b.end(), std::inserter(a, a.end()));
std::move(c.begin(), c.end(), std::inserter(a, a.end()));
b.clear();
c.clear();
Author: vdenotaris, 2013-08-09

4 answers

En mi opinión, tu primera solución es la mejor manera de hacerlo.

vector<>::insert está diseñado para añadir elemento por lo que es la solución más adecuada.

Puedes llamar a reserve en el vector de destino para reservar un poco de espacio, pero a menos que agregues muchos vectores juntos, es probable que no proporcione muchos beneficios: vector<>::insert sepa cuántos elementos se agregarán, evitará solo una llamada reserve.

Nota: Si esos fueran vector de tipo más complejo (es decir, una clase personalizada, o incluso std::string), entonces usar std::move podría proporcionarle un buen aumento de rendimiento, porque evitaría el constructor de copia. Para un vector de int sin embargo, no le dará ningún beneficio.

Nota 2 : Vale la pena mencionar que usar std::move hará que el contenido de su fuente vector sea inutilizable.

 23
Author: Xaqq,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-09 13:26:31

Asumiendo que desea copiar y no mover, esta sería la mejor manera:

a.reserve(a.size()+b.size()+c.size()); // Reserve space first
a.insert(a.end(),b.begin(),b.end());
a.insert(a.end(),c.begin(),c.end());

Si quieres moverte:

a.reserve(a.size()+b.size()+c.size()); // Reserve space first
a.insert(a.end(),std::make_move_iterator(b.begin()),
         std::make_move_iterator(b.end()));
a.insert(a.end(),std::make_move_iterator(c.begin()),
         std::make_move_iterator(c.end()));
b.swap(std::vector<int>()); // Clear and deallocate space
c.swap(std::vector<int>()); // Clear and deallocate space

Update: Has editado tu pregunta varias veces convirtiéndola en un objetivo en movimiento. Su primera opción es ahora muy similar a mi primera sugerencia.

Actualización 2: A partir de C++11, es posible que ya no tenga que usar el truco "intercambiar con vector vacío" para borrar y desasignar espacio, dependiendo de la implementación de su biblioteca de vector. Lo siguiente puede hacer el trabajo de una manera más intuitiva:

// Empty the vectors of objects
b.clear(); 
c.clear();

// Deallocate the memory allocated by the vectors 
// Note: Unlike the swap trick, this is non-binding and any space reduction
//       depends on the implementation of std::vector
b.shrink_to_fit();
c.shrink_to_fit();
 18
Author: Michael Goldshteyn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-21 04:00:36

La primera es la mejor opción porque insert puede averiguar cuántos elementos está agregando y cambiar el tamaño del vector para que quepa antes de que comience a copiar. Los otros no tienen esa información, por lo que podría terminar redimensionando después de un poco de copia, lo que sería más lento que redimensionar al principio, o redimensionar más de una vez.

Sin embargo, como sugiere @michaelgoldshteyn, ya que va a hacer dos inserciones, también puede cambiar el tamaño de la matriz usted mismo con el tamaño final, lo que potencialmente ahorra una redimensionar.

 1
Author: Pete Becker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-09 13:13:49

Si realmente desea agregar los datos de b y c en vector a, tiene que hacer la inserción (que en realidad es su 1.):

a.reserve( a.size() + b.size() + c.size() ); // preallocate memory (see why)
a.insert( a.end(), b.begin(), b.end() );
a.insert( a.end(), c.begin(), c.end() );

Dependiendo del compilador std::copy (su 2.) normalmente debe ser tan rápido.

Dado que un std::vector siempre debe ser contiguo en la memoria, no puede simplemente mover (como se define en C++11) y si conoce el tamaño final debe reservar su vector (evitará reasignaciones innecesarias de su vector). Pero si realmente te preocupas por el rendimiento, deja que esto sea como tres std::vector e itera sobre ellos cuando tengas que leer sus datos.

 0
Author: Kyle_the_hacker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-09 15:20:30