2011-01-18 4 views
29

Tengo una función foo(int[] nums) que entiendo es esencialmente equivalente a foo(int* nums). Dentro de foo necesito copiar el contenido apuntado por nums en algún int[10] declarado dentro del alcance de foo. Entiendo que lo siguiente no es válido:memcpy vs for loop - ¿Cuál es la forma correcta de copiar una matriz desde un puntero?

void foo (int[] nums) 
{ 
    myGlobalArray = *nums 
} 

¿Cuál es la forma correcta de copiar la matriz? ¿Debo usar memcpy como sigue:

void foo (int[] nums) 
{ 
    memcpy(&myGlobalArray, nums, 10); 
} 

o debería usar un bucle for?

void foo(int[] nums) 
{ 
    for(int i =0; i < 10; i++) 
    { 
     myGlobalArray[i] = nums[i]; 
    } 
} 

¿Hay una tercera opción que me falta?

+2

¿Has intentado compilar tus ejemplos? –

+0

duplicado posible de [¿Por qué es memcpy() y memmove() más rápido que los incrementos puntero?] (Http://stackoverflow.com/questions/7776085/why-is-memcpy-and-memmove-faster-than-pointer-increments) Aunque esto no menciona más rápido, ambos fragmentos son funcionalmente correctos, por lo que se reducirá a eso. –

Respuesta

19

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

Su código es incorrecto. Debe ser:

memcpy(&myGlobalArray, nums, 10 * sizeof(int)); 
+0

¡Hola! ¿Por qué Memcpy sería más rápido? – Swanand

+0

Los autores de la biblioteca c han dedicado mucho tiempo a optimizarla. Si escribe código para hacer lo mismo, depende de qué tan bien el compilador optimice su código. – Jay

1

Para el rendimiento, use memcpy (o equivalentes). Se trata de un código específico de la plataforma altamente optimizado para derivar muchos datos rápidamente.

Para su mantenimiento, tenga en cuenta lo que está haciendo: el bucle for puede ser más legible y más fácil de entender. (Conseguir un establecimiento de memoria equivocada es una vía rápida a un accidente o peor)

59

Sí, la tercera opción es utilizar un C++ construcción:

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

con cualquier compilador correcta, esto:

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

También es más rápido: http://stackoverflow.com/questions/4707012/c-memcpy-vs-stdcopy/9980859#9980859 –

+2

Parece que he dejado una palabra importante de ese comentario: "posiblemente" –

+0

@Oliver Charlesworth es '& nums [10]' permitido cuando el tamaño de la matriz es 10? ¿Funcionarían 'nums + 10' en su lugar? – user2635088

1

Esencialmente, siempre y cuando se trata de tipos de POD (llanura Ol' Data), como int, unsigned int, punteros, estructuras de datos solamente, etc ... que están a salvo para usar mem *.

Si su matriz contiene objetos, use el bucle for, ya que el operador = puede ser necesario para garantizar la asignación correcta.

4

En general, el peor de los escenarios será en una compilación de depuración no optimizada donde memcpy no está en línea y puede realizar comprobaciones adicionales de cordura/afirmación que ascienden a un pequeño número de instrucciones adicionales frente a un ciclo for.

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

La gente a menudo tropiezan con el hecho de que los tamaños de establecimiento de memoria en bytes, y escriben cosas como éstas:

// 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í mediante el uso de las características del lenguaje que le permiten hacer un cierto grado de reflexión, que es : hacer las cosas en términos de los datos en sí en lugar de lo que sabe acerca de los datos, ya que en una función genérica por lo general no sabe nada acerca de los datos:

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

Tenga en cuenta que no desea que el " & "delante de" myGlob alArray "porque las matrices decaen automáticamente en punteros; en realidad estaba copiando "nums" a la dirección en la memoria donde se estaba reteniendo el puntero al myGlobalArray [0].

Uso memcpy en objetos puede ser peligroso, tenga en cuenta:

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)); 

Este es el camino equivocado para copiar objetos que no son POD (datos llanura de edad). Tanto f1 como f2 ahora tienen std :: string que cree que posee "hola". Uno de ellos va a bloquearse cuando se destruct, y los dos se creen los dueños del mismo vector de enteros que contiene 42.

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

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

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

struct Foo { 
    int m_i; 
}; 

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

y más tarde en el cambio de Foo para incluir un std::string, su código se romperá. Si en lugar de escribir:

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 hacer lo correcto sin ningún trabajo adicional para usted, y su código es un poco más fácil de leer.

Cuestiones relacionadas