2011-01-18 8 views
29

Ho una funzione foo(int[] nums) che a mio avviso è sostanzialmente equivalente a foo(int* nums). Dentro foo Ho bisogno di copiare il contenuto dell'array puntato da nums in un numero int[10] dichiarato nell'ambito di foo. Comprendo quanto segue non è valido:memcpy vs for loop - Qual è il modo corretto di copiare un array da un puntatore?

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

Qual è il modo corretto di copiare l'array? Dovrei usare memcpy in questo modo:

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

o dovrei usare un ciclo for?

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

C'è una terza opzione che mi manca?

+2

Hai provato a compilare i tuoi esempi? –

+0

Possibile duplicato di [Perché memcpy() e memmove() sono più veloci degli incrementi del puntatore?] (Http://stackoverflow.com/questions/7776085/why-is-memcpy-and-memmove-faster-than-pointer-increments) Sebbene questo non accennino più velocemente, entrambi i frammenti sono funzionalmente corretti, quindi si tratterà di questo. –

risposta

19

Memcpy sarà probabilmente più veloce, ma è più probabile che si commetterà un errore utilizzandolo. Può dipendere da quanto è intelligente il tuo compilatore di ottimizzazione.

Il tuo codice non è corretto. Dovrebbe essere:

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

Ehi! Perché Memcpy sarebbe più veloce ?? – Swanand

+0

Gli autori della libreria c hanno dedicato molto tempo a ottimizzarlo. Se scrivi codice per fare la stessa cosa, dipende da quanto bene il compilatore ottimizza il tuo codice. – Jay

1

Per prestazioni, utilizzare memcpy (o equivalenti). È un codice specifico per piattaforma altamente ottimizzato per lo smistamento di molti dati in tempi rapidi.

Per la manutenibilità, prendere in considerazione ciò che si sta facendo - il ciclo for può essere più leggibile e più facile da capire. (Ottenere un memcpy sbagliata è un percorso veloce di un crash o peggio)

59

Sì, la terza opzione è quella di utilizzare un C++ costrutto:

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

Con qualsiasi compilatore sano di mente, è:

  • dovrebbe essere ottimale nella maggior parte dei casi (compilerà a memcpy() ove possibile),
  • è type-safe,
  • affronta con grazia quando si decide di cambiare ° e data-type a un non-primitivo (es. chiama costruttori di copia, ecc.),
  • si comporta in modo elegante quando si decide di passare a una classe contenitore.
+0

È anche più veloce: http://stackoverflow.com/questions/4707012/c-memcpy-vs-stdcopy/9980859#9980859 –

+2

Mi sembra di aver lasciato una parola importante da quel commento: "possibilmente" –

+0

@Oliver Charlesworth è '& nums [10]' permesso quando la dimensione dell'array è 10? Funzionerebbe invece 'nums + 10'? – user2635088

1

In sostanza, fino a quando si ha a che fare con i tipi di POD (Plain Ol' dati), come int, unsigned int, puntatori, di soli dati struct, ecc ... sei al sicuro usare mem *.

Se la matrice contiene oggetti, utilizzare il ciclo for, poiché l'operatore = potrebbe essere necessario per garantire l'assegnazione corretta.

4

In generale, lo scenario peggiore si trova in una build di debug non ottimizzata in cui memcpy non è in linea e può eseguire ulteriori controlli di integrità/asserzione per un numero limitato di istruzioni aggiuntive rispetto a un ciclo for.

Tuttavia, memcpy è generalmente ben implementato per sfruttare elementi intrinseci, ecc., Ma questo varierà con l'architettura di destinazione e il compilatore. È improbabile che memcpy sarà sempre peggio di un'implementazione for-loop.

La gente spesso inciampare il fatto che le dimensioni memcpy in byte, e scrivono cose come queste:

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

È possibile proteggersi qui utilizzando funzionalità del linguaggio che consentono di fare un certo grado di riflessione, cioè : fare le cose in termini di dati stessi, piuttosto che quello che sai sui dati, perché in una funzione generica in genere non si sa nulla circa i dati:

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

Nota che non si desidera che il " & "davanti a" myGlob alArray "perché gli array decadono automaticamente ai puntatori; in effetti stavi copiando "numeri" all'indirizzo in memoria dove si trovava il puntatore a myGlobalArray [0].

Uso memcpy su oggetti può essere pericoloso, considerare:

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

questo è il modo sbagliato per copiare gli oggetti che non sono POD (dati vecchi pianura). Sia f1 che f2 ora hanno una stringa std :: che pensa che possieda "ciao". Uno di loro sta per bloccarsi quando Destruct, ed entrambi pensano che possiedono lo stesso vettore di interi che contiene 42.

La pratica migliore per C++ i programmatori è quello di utilizzare std::copy:

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

Questo può prendere decisioni sulla durata della compilazione su cosa fare, incluso l'utilizzo di memcpy o memmove e, se possibile, utilizzare potenzialmente le istruzioni SSE/vettoriali. Un altro vantaggio è che se si scrive questo:

struct Foo { 
    int m_i; 
}; 

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

e più tardi sul cambiamento Foo per includere un std::string, il codice si romperà. Se invece scrive:

struct Foo { 
    int m_i; 
}; 

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

il compilatore passerà il codice per fare la cosa giusta, senza alcun lavoro supplementare per voi, e il codice è un po 'più leggibile.

Problemi correlati