memcpy vs for loop:¿cuál es la forma correcta de copiar una matriz desde un puntero?

memcpy vs for loop:¿cuál es la forma correcta de copiar una matriz desde un puntero?

Sí, la tercera opción es usar una construcción de C++:

std::copy(&nums[0], &nums[10], myGlobalArray);

Con cualquier compilador cuerdo:

  • debería ser óptimo en la mayoría de los casos (se compilará en memcpy() donde sea posible),
  • es de tipo seguro,
  • se adapta con gracia cuando decide cambiar el tipo de datos a uno no primitivo (es decir, llama a los constructores de copias, etc.),
  • hace frente con gracia cuando decide cambiar a una clase de contenedor.

Memcpy probablemente será más rápido, pero es más probable que cometa un error al usarlo. Puede depender de qué tan inteligente sea su compilador de optimización.

Sin embargo, su código es incorrecto. Debería ser:

memcpy(myGlobalArray, nums, 10 * sizeof(int) );

En términos generales, el peor de los casos será en una compilación de depuración no optimizada donde memcpy no está en línea y puede realizar verificaciones adicionales de cordura/afirmación que ascienden a una pequeña cantidad de instrucciones adicionales frente a un bucle for.

Sin embargo memcpy generalmente está bien implementado para aprovechar cosas como intrínsecos, etc., pero esto variará con la arquitectura de destino y el compilador. Es poco probable que memcpy nunca será peor que una implementación de bucle for.

La gente a menudo tropieza con el hecho de que memcpy mide en bytes y escribe cosas como estas:

// wrong unless we're copying bytes.
memcpy(myGlobalArray, nums, numNums);
// wrong if an int isn't 4 bytes or the type of nums changed.
memcpy(myGlobalArray, nums, numNums);
// wrong if nums is no-longer an int array.
memcpy(myGlobalArray, nums, numNums * sizeof(int));

Puede protegerse aquí utilizando características del lenguaje que le permitan hacer algún grado de reflexión, es decir:haga las cosas en términos de los datos en sí mismos en lugar de lo que sabe sobre los datos, porque en una función genérica generalmente no sabe nada. sobre los datos:

void foo (int* nums, size_t numNums)
{
    memcpy(myGlobalArray, nums, numNums * sizeof(*nums));
}

Tenga en cuenta que no desea el "&" delante de "myGlobalArray" porque las matrices se descomponen automáticamente en punteros; en realidad estabas copiando "nums" a la dirección en la memoria donde se retenía el puntero a myGlobalArray[0].

(Editar nota:escribiría int[] nums cuando no me refiero a int nums[] pero decidí que agregar el caos de equivalencia de puntero de matriz C no ayudaba a nadie, así que ahora es int *nums :) )

Usando memcpy en objetos puede ser peligroso, considere:

struct Foo {
    std::string m_string;
    std::vector<int> m_vec;
};

Foo f1;
Foo f2;
f2.m_string = "hello";
f2.m_vec.push_back(42);
memcpy(&f1, &f2, sizeof(f2));

Esta es la forma INCORRECTA de copiar objetos que no son POD (datos antiguos simples). Tanto f1 como f2 ahora tienen un std::string que cree que posee "hola". Uno de ellos se estrellará cuando se destruyan, y ambos creen que poseen el mismo vector de números enteros que contiene 42.

La mejor práctica para los programadores de C++ es usar std::copy :

std::copy(nums, nums + numNums, myGlobalArray);

Nota de Remy Lebeau o desde C++11

std::copy_n(nums, numNums, myGlobalArray);

Esto puede tomar decisiones de tiempo de compilación sobre qué hacer, incluido el uso de memcpy o memmove y potencialmente usando SSE/instrucciones vectoriales si es posible. Otra ventaja es que si escribes esto:

struct Foo {
    int m_i;
};

Foo f1[10], f2[10];
memcpy(&f1, &f2, sizeof(f1));

y luego cambia Foo para incluir un std::string , su código se romperá. Si en cambio escribes:

struct Foo {
    int m_i;
};

enum { NumFoos = 10 };
Foo f1[NumFoos], f2[NumFoos];
std::copy(f2, f2 + numFoos, f1);

el compilador cambiará su código para que haga lo correcto sin ningún trabajo adicional para usted, y su código será un poco más legible.