modo rapido per copiare un vettore in un altro


155

Preferisco due modi:

void copyVecFast(const vec<int>& original)
{
  vector<int> newVec;
  newVec.reserve(original.size());
  copy(original.begin(),original.end(),back_inserter(newVec));
}

void copyVecFast(vec<int>& original)
{

  vector<int> newVec;
  newVec.swap(original); 
}

Come si fa?


14
Il secondo ha un nome fuorviante, in quanto non è una copia (anche se è veloce).
Anonimo

Risposte:


125

Il tuo secondo esempio non funziona se si invia l'argomento per riferimento. Intendevi

void copyVecFast(vec<int> original) // no reference
{

  vector<int> new_;
  new_.swap(original); 
}

Funzionerebbe, ma è un modo più semplice

vector<int> new_(original);

Bene, funziona. Ma non funziona per una serie di vettori: ad esempio: vector <int> A [n];
ABcDexter,

8
Questo è scambio, non copia.
sdd

1
@sdd - no non lo è. Controlla l'elenco degli argomenti. originalè una copia dell'argomento della funzione.
rlbond

@rlbond Ha annullato accidentalmente la risposta :(, puoi per favore modificare il post, in modo che io possa rimuovere il
voto negativo

250

Non sono uguali, vero? Uno è una copia, l'altro è uno scambio . Da qui i nomi delle funzioni.

Il mio preferito è:

a = b;

Dove ae bsono i vettori.


3
In realtà l'approccio passa per valore, il compilatore chiama il costruttore della copia e quindi scambia l'elemento appena creato. Ecco perché rlbond suggerisce di chiamare direttamente il costruttore di copie per ottenere lo stesso effetto.
David Rodríguez - dribeas,

1
Tuttavia, non è possibile chiamare rlbon senza una funzione che passa l'originale come val. Altrimenti, quello originale sarà vuoto. La seconda soluzione ha assicurato che chiamerai sempre per valore e quindi non perderai la data nel vettore originale. (Supponendo che lo scambio si occupi di puntatori)
Eyad Ebrahim

Questo non sposta gli elementi di b in a (lasciando b con dimensione == 0)?
Jonathan.

1
@Jonathan. Supponendo che tu stia parlando a = ballora no. Assegnazione significa: rendere auguale bsenza cambiare b. Al contrario, std::swap(a, b)sarebbe scambiare i loro contenuti (in modo b's sizeora sarebbe tutto ciò che a' s era stato prima). Stai forse pensando a un'operazione di spostamento (come accade in C ++ 11, ma non in un compito ordinario come questo). Una tale mossa avrebbe lasciato bin una, ahem, stato "interessante" - vedi stackoverflow.com/questions/17730689/...
Daniel Earwicker

1
@Jonathan. Nota la doppia e commerciale &&. Quella versione verrà utilizzata solo per un riferimento al valore. Non corrisponderà a nessun valore non const (come bnel mio esempio sopra). Puoi trasformarlo bin uno dicendo a = std::move(b);Vedi en.cppreference.com/w/cpp/language/value_category per livelli di complessità ancora maggiori.
Daniel Earwicker,

74

Questo è un altro modo valido per fare una copia di un vettore, basta usare il suo costruttore:

std::vector<int> newvector(oldvector);

Questo è ancora più semplice rispetto all'uso std::copydi percorrere l'intero vettore dall'inizio alla fine verso di std::back_insertloro nel nuovo vettore.

Detto questo, il tuo .swap()non è una copia, ma scambia i due vettori. Modificare l'originale per non contenere più nulla! Che non è una copia.


Più flessibile per me è a = b;perché ho già un campo membro ae devo solo assegnarlo con il nuovo valore dab
truthadjustr

20

Risposta diretta:

  • Usa un =operatore

Possiamo usare la funzione membro pubblico std::vector::operator=del contenitore std::vectorper assegnare valori da un vettore a un altro.

  • Utilizzare una funzione di costruzione

Inoltre, ha senso anche una funzione di costruzione. Una funzione di costruzione con un altro vettore come parametro (ad es. x) Costruisce un contenitore con una copia di ciascuno degli elementi nello xstesso ordine.

Attenzione:

  • Non usare std::vector::swap

std::vector::swapnon sta copiando un vettore in un altro, sta in realtà scambiando elementi di due vettori, proprio come suggerisce il nome. In altre parole, il vettore di origine da cui copiare viene modificato dopo la std::vector::swapchiamata, il che probabilmente non è quello previsto.

  • Copia profonda o superficiale?

Se gli elementi nel vettore di origine sono puntatori ad altri dati, a volte è richiesta una copia approfondita.

Secondo Wikipedia:

Una copia profonda, nel senso che i campi sono sottoposti a dereferenziazione: anziché i riferimenti agli oggetti da copiare, vengono creati nuovi oggetti copia per qualsiasi oggetto referenziato e riferimenti a questi posizionati in B.

In realtà, al momento non esiste un modo integrato in C ++ per eseguire una copia approfondita. Tutti i modi sopra menzionati sono superficiali. Se è necessaria una copia profonda, è possibile attraversare un vettore ed eseguire manualmente la copia dei riferimenti. In alternativa, un iteratore può essere considerato per l'attraversamento. La discussione su iteratore va oltre questa domanda.

Riferimenti

La pagina di std::vectorsu cplusplus.com


14

non dovresti usare lo scambio per copiare i vettori, cambierebbe il vettore "originale".

passa invece l'originale come parametro al nuovo.


14
new_vector.assign(old_vector.begin(),old_vector.end()); // Method 1
new_vector = old_vector; // Method 2

-14

Nel caso in cui esistesse già il vettore e tu volessi semplicemente copiare, puoi farlo:

newVec.resize(oldVec.size());
memcpy(&newVec.at(0), &oldVec.at(0), oldVec.size());

1
Per favore, non memcpy. Inoltre, questo non funzionerà poiché memcpy assume la dimensione in byte. Inoltre, se l'altro vettore esiste già, puoi semplicemente fare newVec = oldVeclo stesso di una delle altre risposte.
FDinoff,

Si hai ragione. Non l'ho visto. @FDinoff, sebbene sotto uno funzioni, perché suggerisci di non usare memcpy? Sembra essere molto più veloce di newVec = oldVec. memcpy (& newVec.at (0), & oldVec.at (0), oldVec.size () * sizeof (int));
sgowd,

1
Nel caso generale, copiare un oggetto senza chiamare il suo costruttore di copia potrebbe portare a bug sottili. In questo caso avrei pensato che avrebbero avuto le stesse prestazioni. In caso contrario, direi che il vettore non era ottimizzato per le prestazioni, dal momento che avrebbe già dovuto farlo. Hai davvero scritto un benchmark?
FDinoff,

Non ti stavo criticando. Anche la mia guida ha suggerito lo stesso e stavo cercando di capire.
sgowd,

(Non pensavo mi stessi criticando.) C'è ancora qualcosa che non capisci?
FDinoff,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.