¿Cómo se copia el contenido de una matriz a un std :: vector en C ++ sin bucle?

StackOverflow https://stackoverflow.com/questions/259297

  •  06-07-2019
  •  | 
  •  

Pregunta

Tengo una matriz de valores que se pasa a mi función desde una parte diferente del programa que necesito almacenar para su posterior procesamiento. Como no sé cuántas veces se llamará a mi función antes de que sea hora de procesar los datos, necesito una estructura de almacenamiento dinámica, por lo que elegí un std :: vector . No quiero tener que hacer el bucle estándar para push_back todos los valores individualmente, sería bueno si pudiera copiarlo todo usando algo similar a memcpy .

¿Fue útil?

Solución

Si puede construir el vector después de haber obtenido la matriz y el tamaño de la matriz, puede decir:

std::vector<ValueType> vec(a, a + n);

... suponiendo que a es su matriz y n es la cantidad de elementos que contiene. De lo contrario, std :: copy () w / resize () hará el truco.

Me mantendría alejado de memcpy () a menos que pueda estar seguro de que los valores son tipos de datos simples (POD).

Además, vale la pena señalar que ninguno de estos realmente evita el bucle for: es solo una cuestión de si tiene que verlo en su código o no. O (n) el rendimiento en tiempo de ejecución es inevitable para copiar los valores.

Finalmente, tenga en cuenta que las matrices de estilo C son contenedores perfectamente válidos para la mayoría de los algoritmos STL: el puntero sin formato es equivalente a begin () y ( ptr + n ) es equivalente a end () .

Otros consejos

Ha habido muchas respuestas aquí y casi todas ellas harán el trabajo.

¡Sin embargo, hay algunos consejos engañosos!

Estas son las opciones:

vector<int> dataVec;

int dataArray[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
unsigned dataArraySize = sizeof(dataArray) / sizeof(int);

// Method 1: Copy the array to the vector using back_inserter.
{
    copy(&dataArray[0], &dataArray[dataArraySize], back_inserter(dataVec));
}

// Method 2: Same as 1 but pre-extend the vector by the size of the array using reserve
{
    dataVec.reserve(dataVec.size() + dataArraySize);
    copy(&dataArray[0], &dataArray[dataArraySize], back_inserter(dataVec));
}

// Method 3: Memcpy
{
    dataVec.resize(dataVec.size() + dataArraySize);
    memcpy(&dataVec[dataVec.size() - dataArraySize], &dataArray[0], dataArraySize * sizeof(int));
}

// Method 4: vector::insert
{
    dataVec.insert(dataVec.end(), &dataArray[0], &dataArray[dataArraySize]);
}

// Method 5: vector + vector
{
    vector<int> dataVec2(&dataArray[0], &dataArray[dataArraySize]);
    dataVec.insert(dataVec.end(), dataVec2.begin(), dataVec2.end());
}

Para abreviar una larga historia, el Método 4, usando vector :: insert, es lo mejor para el escenario de bsruth.

Aquí hay algunos detalles sangrientos:

Método 1 es probablemente el más fácil de entender. Simplemente copie cada elemento de la matriz y empújelo hacia la parte posterior del vector. Por desgracia, es lento. Debido a que hay un bucle (implícito con la función de copia), cada elemento debe tratarse individualmente; no se pueden realizar mejoras de rendimiento debido al hecho de que sabemos que la matriz y los vectores son bloques contiguos.

Método 2 es una mejora de rendimiento sugerida para el Método 1; simplemente reserve previamente el tamaño de la matriz antes de agregarlo. Para matrices grandes, esto podría ayudar. Sin embargo, el mejor consejo aquí es nunca usar la reserva a menos que el perfil sugiera que puede obtener una mejora (o necesita asegurarse de que sus iteradores no se invaliden). Bjarne está de acuerdo . Por cierto, descubrí que este método realizó el más lento la mayor parte del tiempo, aunque estoy luchando por explicar exhaustivamente por qué era regularmente significativamente más lento que el método 1 ...

Método 3 es la solución de la vieja escuela: ¡arroje un poco de C al problema! Funciona bien y rápido para los tipos de POD. En este caso, se requiere llamar a redimensionar ya que memcpy funciona fuera de los límites del vector y no hay forma de decirle a un vector que su tamaño ha cambiado. Además de ser una solución fea (¡copia de bytes!) Recuerda que esto solo se puede usar para tipos de POD . Nunca usaría esta solución.

Método 4 es la mejor manera de hacerlo. Su significado es claro, es (generalmente) el más rápido y funciona para cualquier objeto. No hay inconvenientes en el uso de este método para esta aplicación.

Método 5 es un ajuste en el Método 4: copie la matriz en un vector y luego añádala. Buena opción, generalmente rápida y clara.

Finalmente, sabe que puede usar vectores en lugar de matrices, ¿verdad? Incluso cuando una función espera matrices de estilo c, puede usar vectores:

vector<char> v(50); // Ensure there's enough space
strcpy(&v[0], "prefer vectors to c arrays");

¡Espero que ayude a alguien por ahí!

Si todo lo que está haciendo es reemplazar los datos existentes, puede hacerlo

std::vector<int> data; // evil global :)

void CopyData(int *newData, size_t count)
{
   data.assign(newData, newData + count);
}

std :: copy es lo que está buscando.

Como solo puedo editar mi propia respuesta, voy a hacer una respuesta compuesta de las otras respuestas a mi pregunta. Gracias a todos los que respondieron.

Usando std :: copy , esto todavía se repite en el fondo, pero no tiene que escribir el código.

int foo(int* data, int size)
{
   static std::vector<int> my_data; //normally a class variable
   std::copy(data, data + size, std::back_inserter(my_data));
   return 0;
}

Uso de memcpy normal. Probablemente se utilice mejor para tipos de datos básicos (es decir, int), pero no para conjuntos más complejos de estructuras o clases.

vector<int> x(size);
memcpy(&x[0], source, size*sizeof(int));
int dataArray[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };//source

unsigned dataArraySize = sizeof(dataArray) / sizeof(int);

std::vector<int> myvector (dataArraySize );//target

std::copy ( myints, myints+dataArraySize , myvector.begin() );

//myvector now has 1,2,3,...10 :-)

evita la memoria, digo. No hay razón para meterse con operaciones de puntero a menos que realmente tenga que hacerlo. Además, solo funcionará para los tipos de POD (como int), pero fallaría si se trata de tipos que requieren construcción.

Además de los métodos presentados anteriormente, debe asegurarse de usar std :: Vector.reserve (), std :: Vector.resize (), o construir el vector a medida, para asegurarse de que su vector tenga suficientes elementos para contener sus datos. si no, corromperás la memoria. Esto es cierto para std :: copy () o memcpy ().

Esta es la razón para usar vector.push_back (), no puedes escribir más allá del final del vector.

Otra respuesta más, ya que la persona dijo "No sé cuántas veces se llamará a mi función", podría usar el método de inserción de vectores de esta manera para agregar matrices de valores al final del vector:

vector<int> x;

void AddValues(int* values, size_t size)
{
   x.insert(x.end(), values, values+size);
}

Me gusta de esta manera porque la implementación del vector debería ser capaz de optimizar la mejor manera de insertar los valores basados ??en el tipo de iterador y el tipo en sí. Estás respondiendo algo sobre la implementación de stl.

Si necesita garantizar la velocidad más rápida y sabe que su tipo es un tipo POD, entonces recomendaría el método de cambio de tamaño en la respuesta de Thomas:

vector<int> x;

void AddValues(int* values, size_t size)
{
   size_t old_size(x.size());
   x.resize(old_size + size, 0);
   memcpy(&x[old_size], values, size * sizeof(int));
}

Suponiendo que sabe cuán grande es el elemento en el vector:

std::vector<int> myArray;
myArray.resize (item_count, 0);
memcpy (&myArray.front(), source, item_count * sizeof(int));

http://www.cppreference.com/wiki/stl/vector/start

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top