maneira rápida de copiar um vetor para outro


155

Eu prefiro duas maneiras:

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

Como você faz isso?


14
O segundo tem um nome enganador - pois não é uma cópia (embora seja rápida).
Anônimo

Respostas:


125

Seu segundo exemplo não funcionará se você enviar o argumento por referência. Você quis dizer

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

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

Isso funcionaria, mas uma maneira mais fácil é

vector<int> new_(original);

Bom, funciona. Mas não está funcionando para uma matriz de vetores: por exemplo: vetor <int> A [n];
ABcDexter

8
Isso é troca, não cópia.
sdd

1
@ SDD - não, não é. Verifique a lista de argumentos. originalé uma cópia do argumento da função
rlbond

250

Eles não são os mesmos, são? Um é uma cópia, o outro é uma troca . Daí os nomes das funções.

Meu favorito é:

a = b;

Onde ae bsão vetores.


3
De fato, a abordagem está passando por valor, o compilador chama o construtor de cópia e depois troca esse elemento recém-criado. É por isso que o rlbond sugere chamar o construtor de cópia diretamente para obter o mesmo efeito.
David Rodríguez - dribeas 14/03/09

1
No entanto, você não pode chamar rlbon sem uma função que passe o original como val. Caso contrário, o original será vazio. A segunda solução garantiu que você sempre chamaria por valor e, portanto, não perderia a data no vetor original. (Assumindo acordos de swap com ponteiros) #
Eyad Ebrahim 31/03

Isso não moverá os elementos de b para a (deixando b com tamanho == 0)?
Jonathan.

1
@Jonathan. Supondo que você esteja falando, a = bentão não. Atribuição significa: fazer aigual bsem mudar b. Por outro lado, std::swap(a, b)seria trocar seu conteúdo (por isso b's sizeagora seria tudo o que a' s tinha sido antes). Talvez você esteja pensando em uma operação de movimentação (como ocorre no C ++ 11, mas não em uma tarefa comum como essa). Tal movimento deixaria bem um, ahem, estado "interessante" - veja stackoverflow.com/questions/17730689/…
Daniel Earwicker

1
@Jonathan. Observe o duplo e comercial &&. Essa versão será usada apenas para uma referência rvalue. Não corresponderá a nenhum valor que não seja const (como bno meu exemplo acima). Você pode se transformar bem um dizendo a = std::move(b);See en.cppreference.com/w/cpp/language/value_category para níveis de complexidade ainda maiores.
Daniel Earwicker

74

Esta é outra maneira válida de fazer uma cópia de um vetor, basta usar seu construtor:

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

Isso é ainda mais simples do que usar std::copypara mover o vetor inteiro do início ao fim até std::back_inserto novo vetor.

Dito isto, o seu .swap()não é uma cópia, mas troca os dois vetores. Você modificaria o original para não conter mais nada! O que não é uma cópia.


Mais flexível para mim é a = b;porque eu já tenho um campo de membro ae só preciso atribuí-lo com o novo valor deb
truthadjustr

20

Resposta direta:

  • Use um =operador

Podemos usar a função std::vector::operator=de membro pública do contêiner std::vectorpara atribuir valores de um vetor para outro.

  • Use uma função construtora

Além disso, uma função construtora também faz sentido. Uma função construtora com outro vetor como parâmetro (por exemplo x) constrói um contêiner com uma cópia de cada um dos elementos x, na mesma ordem.

Cuidado:

  • Não use std::vector::swap

std::vector::swapnão está copiando um vetor para outro, na verdade está trocando elementos de dois vetores, exatamente como o nome sugere. Em outras palavras, o vetor de origem para copiar é modificado após std::vector::swapser chamado, o que provavelmente não é o que você espera.

  • Cópia profunda ou rasa?

Se os elementos no vetor de origem são ponteiros para outros dados, algumas vezes é necessária uma cópia em profundidade.

De acordo com a wikipedia:

Uma cópia profunda, significando que os campos são desreferenciados: em vez de referências a objetos que estão sendo copiados, novos objetos de cópia são criados para quaisquer objetos referenciados e referências a esses colocados em B.

Atualmente, não há atualmente uma maneira interna em C ++ para fazer uma cópia profunda. Todas as formas mencionadas acima são superficiais. Se uma cópia profunda for necessária, você pode percorrer um vetor e fazer cópia das referências manualmente. Como alternativa, um iterador pode ser considerado para atravessar. A discussão sobre o iterador está além desta questão.

Referências

A página de std::vectorem cplusplus.com


14

você não deve usar swap para copiar vetores, isso mudaria o vetor "original".

passe o original como parâmetro para o novo.


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

-14

Caso o vetor JÁ existisse e você quisesse apenas copiar, você poderia fazer o seguinte:

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

1
Por favor, não memcpy. Além disso, isso não funcionará, pois o memcpy assume o tamanho em bytes. Além disso, se o outro vetor já existir, você poderá fazer newVec = oldVeco mesmo que uma das outras respostas.
FDinoff 29/09/2015

Sim você está certo. Eu não vi isso. @FDinoff, embora abaixo de um funcione, por que você sugere não usar o memcpy? Parece ser muito mais rápido que newVec = oldVec. memcpy (& newVec.at (0), & oldVec.at (0), oldVec.size () * sizeof (int));
sgowd

1
No caso geral, copiar um objeto sem chamar seu construtor de cópias pode levar a erros sutis. Nesse caso, eu pensaria que eles teriam o mesmo desempenho. Caso contrário, diria que o vetor não foi otimizado para desempenho, pois já deveria estar fazendo isso. Você realmente escreveu uma referência?
FDinoff

Eu não estava criticando você. O líder da minha equipe também sugeriu o mesmo e eu estava tentando entender.
sgowd

(Eu não pensei que você estivesse me criticando.) Ainda há algo que você não entende?
FDinoff
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.