web-dev-qa-db-fra.com

Comment copier le contenu d'un tableau dans un std :: vector en C ++ sans effectuer de boucle?

J'ai un tableau de valeurs qui est transmis à ma fonction à partir d'une partie différente du programme que je dois stocker pour un traitement ultérieur. Étant donné que je ne sais pas combien de fois ma fonction sera appelée avant le moment du traitement des données, j'ai besoin d'une structure de stockage dynamique. J'ai donc choisi un std::vector. Je ne veux pas avoir à faire la boucle standard pour Push_back toutes les valeurs individuellement, ce serait bien si je pouvais tout copier en utilisant quelque chose de similaire à memcpy.

101
bsruth

Si vous pouvez construire le vecteur après avoir obtenu le tableau et sa taille, vous pouvez simplement dire:

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

... en supposant que a est votre tableau et n est le nombre d'éléments qu'il contient. Sinon, std::copy() w/resize() fera l'affaire.

Je resterais loin de memcpy() sauf si vous pouvez être sûr que les valeurs sont des types de données en clair (POD).

En outre, il est à noter qu’aucune de ces solutions n’évite réellement la boucle for; il s’agit simplement de savoir si vous devez la voir dans votre code ou non. O(n)) Les performances d'exécution sont inévitables pour la copie des valeurs.

Enfin, notez que les tableaux de style C sont des conteneurs parfaitement valides pour la plupart des algorithmes STL - le pointeur brut est équivalent à begin(), et (ptr + n) Est équivalent à end().

99
Drew Hall

Il y a eu beaucoup de réponses ici et à peu près toutes vont faire le travail.

Cependant, il y a des conseils trompeurs!

Voici les options:

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

Pour couper un long récit La méthode 4, en utilisant vector :: insert, est la meilleure solution pour le scénario de bsruth.

Voici quelques détails sanglants:

Méthode 1 est probablement le plus facile à comprendre. Il suffit de copier chaque élément du tableau et de le placer à l’arrière du vecteur. Hélas, c'est lent. Comme il y a une boucle (implicite avec la fonction copy), chaque élément doit être traité individuellement; aucune amélioration des performances ne peut être réalisée sur la base du fait que nous savons que le tableau et les vecteurs sont des blocs contigus.

Méthode 2 suggère une amélioration des performances par rapport à la méthode 1; il suffit de réserver à l'avance la taille du tableau avant de l'ajouter. Pour les grands tableaux, cela pourrait aider. Cependant, le meilleur conseil ici est de ne jamais utiliser de réserve, sauf si le profilage suggère que vous pourriez obtenir une amélioration (ou vous devez vous assurer que vos itérateurs ne seront pas invalidés). Bjarne accepte . Incidemment, j’ai trouvé que cette méthode exécutait la la plus lente la plupart du temps, bien que j’ai du mal à expliquer en détail pourquoi elle était régulièrement significativement plus lente que la méthode 1. ..

Méthode 3 est l'ancienne solution - jetez un peu de C au problème! Fonctionne bien et rapidement pour les types de POD. Dans ce cas, redimensionner doit être appelé car memcpy fonctionne en dehors des limites du vecteur et il n’ya aucun moyen de dire à un vecteur que sa taille a changé. En plus d’être une solution laide (copie d’octets!), Rappelez-vous que cela peut ne peut être utilisé que pour les types POD. Je n'utiliserais jamais cette solution.

Méthode 4 est la meilleure voie à suivre. Sa signification est claire, c'est (généralement) le plus rapide et cela fonctionne pour tous les objets. Il n'y a aucun inconvénient à utiliser cette méthode pour cette application.

Method 5 est un Tweak on Method 4 - copiez le tableau dans un vecteur puis ajoutez-le. Bonne option - généralement rapide et clair.

Enfin, vous savez que vous pouvez utiliser des vecteurs à la place des tableaux, non? Même lorsqu'une fonction attend des tableaux de style c, vous pouvez utiliser des vecteurs:

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

J'espère que cela aide quelqu'un là-bas!

191
MattyT

Si vous ne faites que remplacer les données existantes, vous pouvez le faire.

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

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

std :: copy est ce que vous cherchez.

11
luke

Comme je ne peux que modifier ma propre réponse, je vais faire une réponse composite à partir des autres réponses à ma question. Merci à tous ceux qui ont répondu.

En utilisant std :: copy , cela itère toujours en arrière-plan, mais vous n'avez pas à taper le code.

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

Utilisation régulière memcpy . Ceci est probablement mieux utilisé pour les types de données de base (c'est-à-dire int) mais pas pour les tableaux plus complexes de structures ou de classes.

vector<int> x(size);
memcpy(&x[0], source, size*sizeof(int));
6
bsruth
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 :-)
5
Antonio Ramasco

évitez la mémoire, dis-je. Aucune raison de gâcher les opérations de pointeur à moins que vous n'y soyez obligé. En outre, cela ne fonctionnera que pour les types de POD (comme int), mais échouera si vous traitez avec des types nécessitant une construction.

3
Assaf Lavie

Encore une autre réponse, puisque la personne a dit "Je ne sais pas combien de fois ma fonction sera appelée", vous pouvez utiliser la méthode d'insertion de vecteur comme ceci pour ajouter des tableaux de valeurs à la fin du vecteur:

vector<int> x;

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

J'aime cette façon parce que l'implémentation du vecteur devrait pouvoir optimiser la meilleure façon d'insérer les valeurs en fonction du type d'itérateur et du type lui-même. Vous répondez quelque peu sur la mise en œuvre de stl.

Si vous avez besoin de garantir la vitesse la plus rapide et que vous savez que votre type est un type de POD, je vous recommanderais la méthode de redimensionnement dans la réponse 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));
}
2
Shane Powell

En plus des méthodes présentées ci-dessus, vous devez vous assurer d'utiliser std :: Vector.reserve (), std :: Vector.resize () ou de construire le vecteur à la taille voulue pour vous assurer qu'il contient suffisamment d'éléments. il pour contenir vos données. sinon, vous allez corrompre la mémoire. Cela est vrai de std :: copy () ou de memcpy ().

C'est la raison d'utiliser vector.Push_back (), vous ne pouvez pas écrire au-delà de la fin du vecteur.

1
Thomas Jones-Low

En supposant que vous sachiez quelle est la taille de l'élément dans le vecteur:

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

0
Thomas Jones-Low