Como você copiar o conteúdo de uma matriz para um std :: vector em C ++ sem loop?

StackOverflow https://stackoverflow.com/questions/259297

  •  06-07-2019
  •  | 
  •  

Pergunta

Eu tenho uma matriz de valores que é passada para minha função de uma parte diferente do programa que eu preciso loja para processamento posterior. Desde que eu não sei quantas vezes minha função será chamado antes que seja tempo para processar os dados, eu preciso de uma estrutura de armazenamento dinâmico, então eu escolhi um std::vector. Eu não quero ter que fazer o ciclo padrão para push_back todos os valores individualmente, seria bom se eu pudesse simplesmente copiar tudo usando algo semelhante ao memcpy.

Foi útil?

Solução

Se você pode construir o vector depois de ter conseguido o tamanho de matriz e array, você pode simplesmente dizer:

std::vector<ValueType> vec(a, a + n);

... assumindo a é sua matriz e n é o número de elementos que ele contém. Caso contrário, std::copy() w / resize() irá fazer o truque.

Eu ficaria longe memcpy() a menos que você pode ter certeza que os valores são dados simples de idade tipos (POD).

Além disso, vale a pena notar que nenhum destes realmente evita o loop - é apenas uma questão de saber se você tem que vê-lo em seu código ou não. O (n) o desempenho de tempo de execução é inevitável para copiar os valores.

Finalmente, nota que as matrizes de estilo C são perfeitamente recipientes válidos para a maioria dos algoritmos STL -. O ponteiro bruto é equivalente a begin(), e (ptr + n) é equivalente a end()

Outras dicas

Houve muitas respostas aqui e apenas sobre todos eles vão fazer o trabalho.

No entanto, há alguns conselhos enganosa!

Aqui estão as opções:

vector<int> dataVec;

int dataArray[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
unsigned dataArraySize = sizeof(dataArray) / sizeof(int);

// Method 1: Copy the array to the vector using back_inserter.
{
    copy(&dataArray[0], &dataArray[dataArraySize], back_inserter(dataVec));
}

// Method 2: Same as 1 but pre-extend the vector by the size of the array using reserve
{
    dataVec.reserve(dataVec.size() + dataArraySize);
    copy(&dataArray[0], &dataArray[dataArraySize], back_inserter(dataVec));
}

// Method 3: Memcpy
{
    dataVec.resize(dataVec.size() + dataArraySize);
    memcpy(&dataVec[dataVec.size() - dataArraySize], &dataArray[0], dataArraySize * sizeof(int));
}

// Method 4: vector::insert
{
    dataVec.insert(dataVec.end(), &dataArray[0], &dataArray[dataArraySize]);
}

// Method 5: vector + vector
{
    vector<int> dataVec2(&dataArray[0], &dataArray[dataArraySize]);
    dataVec.insert(dataVec.end(), dataVec2.begin(), dataVec2.end());
}

Para cortar uma longa história curta Método 4, usando vector :: insert, é a melhor para o cenário de bsruth.

Aqui estão alguns detalhes sórdidos:

Método 1 é provavelmente o mais fácil de entender. Basta copiar cada elemento da matriz e empurrá-lo para a parte de trás do vector. Infelizmente, ele é lento. Porque não há um lacete (implícita com a função de cópia), cada elemento tem de ser tratados individualmente; há melhorias de desempenho pode ser feita com base no fato de que sabemos a matriz e vetores são blocos contíguos.

Método 2 é uma melhoria de desempenho sugeriu ao método 1; apenas pré-reservar o tamanho da matriz antes de adicioná-la. Para grandes matrizes esta , Poder Ajuda. No entanto, o melhor conselho é nunca reserva de uso a menos de perfil sugere que você pode ser capaz de obter uma melhoria (ou o que você precisa para garantir que seus iteradores não vão ser invalidado). Bjarne concorda . Aliás, eu achei que este método realizado o mais lento na maioria das vezes que eu estou lutando para abrangente explicar por que era regularmente significativamente mais lento do que o método 1 ...

Método 3 é a solução velha escola - jogar um pouco de C para o problema! Funciona bem e rápido para os tipos de PI. Neste caso de redimensionamento é necessário para ser chamado desde memcpy funciona fora dos limites do vector e não há maneira de dizer um vetor que seu tamanho mudou. Além de ser uma solução feia (cópia byte!) Lembre-se que isso pode só pode ser usado para tipos POD . Eu nunca usaria essa solução.

Método 4 é o melhor caminho a percorrer. É de significado é claro, é (geralmente) o mais rápido e ele funciona para todos os objetos. Não há desvantagem de usar este método para esta aplicação.

Método 5 é um tweak no Método 4 - copiar a matriz em um vetor e, em seguida, anexá-lo. Boa opção - geralmente fast-ish e clara.

Finalmente, você está ciente que você pode usar vetores no lugar de matrizes, certo? Mesmo quando a função espera matrizes c-estilo você pode usar vetores:

vector<char> v(50); // Ensure there's enough space
strcpy(&v[0], "prefer vectors to c arrays");

Espero que ajude alguém lá fora!

Se tudo que você está fazendo está substituindo os dados existentes, então você pode fazer isso

std::vector<int> data; // evil global :)

void CopyData(int *newData, size_t count)
{
   data.assign(newData, newData + count);
}

std :: copiar é o que você está procurando.

Desde que eu só pode editar a minha própria resposta, eu vou fazer uma resposta composta das outras respostas para minha pergunta. Graças a todos vocês que respondeu.

Usando std :: copy , isso ainda repete em segundo plano, mas você não tem que digitar o código.

int foo(int* data, int size)
{
   static std::vector<int> my_data; //normally a class variable
   std::copy(data, data + size, std::back_inserter(my_data));
   return 0;
}

Usando regulares memcpy . Isso provavelmente melhor é usado para tipos de dados básicos (ou seja, int), mas não para matrizes mais complexas de estruturas ou classes.

vector<int> x(size);
memcpy(&x[0], source, size*sizeof(int));
int dataArray[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };//source

unsigned dataArraySize = sizeof(dataArray) / sizeof(int);

std::vector<int> myvector (dataArraySize );//target

std::copy ( myints, myints+dataArraySize , myvector.begin() );

//myvector now has 1,2,3,...10 :-)

evitar a memcpy, eu digo. Não há razão para mexer com operações do ponteiro menos que você realmente precisa. Além disso, ele só vai funcionar para tipos POD (como int), mas seria um fracasso se você está lidando com os tipos que exigem construção.

Além dos métodos apresentados acima, você precisa ter certeza de que você usar std :: Vector.reserve (), std :: Vector.resize (), ou construir o vetor de tamanho, para se certificar de seu vetor tem elementos suficientes no que ele mantenha seus dados. se não, você vai corromper a memória. Isto é verdade para qualquer std :: copy () ou memcpy ().

Esta é a razão para usar vector.push_back (), você não pode escrever passado o fim do vetor.

No entanto, outra resposta, desde que a pessoa disse: "Eu não sei quantas vezes minha função será chamada", você poderia usar o vetor de inserção método como por assim matrizes anexas dos valores para o final do vetor:

vector<int> x;

void AddValues(int* values, size_t size)
{
   x.insert(x.end(), values, values+size);
}

Eu gosto dessa maneira porque a implementação do vetor deve ser capaz de otimizar a melhor maneira de inserir os valores com base no tipo iterator eo próprio tipo. Você está um pouco respondendo sobre a implementação da STL.

Se você precisa para garantir a velocidade mais rápida e você sabe que seu tipo é um tipo POD, então eu recomendo o método de redimensionamento na resposta de Thomas:

vector<int> x;

void AddValues(int* values, size_t size)
{
   size_t old_size(x.size());
   x.resize(old_size + size, 0);
   memcpy(&x[old_size], values, size * sizeof(int));
}

Assumindo que você sabe o quão grande o item no vector são:

std::vector<int> myArray;
myArray.resize (item_count, 0);
memcpy (&myArray.front(), source, item_count * sizeof(int));

http://www.cppreference.com/wiki/stl/vector/start

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top