2017-02-04 2 views
4

Si je réserve de l'espace pour un vecteur, puis je copie des valeurs avec std::copy_n(), les valeurs sont copiées correctement et accessibles, mais la taille du vecteur est toujours zéro. Est-ce le comportement attendu? Dois-je redimensionner le vecteur, même s'il n'est pas aussi efficace?std :: copy_n ne change pas la taille du vecteur de destination

#include <algorithm> 
#include <iostream> 
#include <vector> 

int main() 
{ 
    std::vector<double> src, dest; 

    for(double x = 0.0; x < 100.0; ++x) 
     src.push_back(x); 

    dest.reserve(src.size()); 

    std::copy_n(src.cbegin(), src.size(), dest.begin()); 

    std::cout << "src.size() = " << src.size() << std::endl; 
    std::cout << "dest.size() = " << dest.size() << std::endl; 

    for(size_t i = 0; i < src.size(); ++i) 
     std::cout << dest[i] << " "; 

} 

Compilateurs testés: clang, gcc, Visual C++

+0

Je pense que le 'réserve()' affecte uniquement la capacité, pas la taille. –

+0

@RawN, oui, mais je m'attendais 'copy_n' à mettre à jour la taille. – Pietro

+0

Vous savez que vous pouvez simplement faire dest = src? Vous connaissez la fonction assign du vecteur? –

Répondre

5

mais la taille du vecteur est encore nul

std::copy_n ne changera pas la taille du conteneur, il suffit de copier la valeur et le pas les itérateurs; il n'a même aucune information sur le conteneur. Donc, le code a un comportement indéfini, même si cela semble fonctionner correctement.

Dois-je redimensionner le vecteur, même s'il n'est pas aussi efficace?

Oui, vous pouvez utiliser std::vector::resize au lieu de std::vector::reserve pour résoudre le problème. Comme vous avez pu le penser, cela signifie que tous les éléments seront construits par resize d'abord, puis assignés par copy_n. Vous pouvez utiliser std::back_inserter, qui ajoutera des éléments à la fin du conteneur en invoquant la fonction membre push_back() du conteneur (à savoir les éléments de construction directement), augmentant ainsi la taille du conteneur. par exemple.

dest.reserve(src.size()); 
std::copy_n(src.cbegin(), src.size(), std::back_inserter(dest)); 
+0

Est-ce que 'std :: back_inserter' n'est pas plus lent que' std :: vetor :: resize' et que vous copiez? –

+0

@KamilKoczurek Non. Il invoquera 'push_back' du conteneur pour ajouter directement les éléments; au lieu de construire tous les éléments par 'resize' et ensuite les assigner. – songyuanyao

+0

À droite, je ne me suis pas rendu compte que vous appelez 'std :: vetor :: reserve', donc il n'y a pas besoin de ré-allouer de la mémoire, mon mauvais. –

0

A std :: vecteur a une taille et une capacité . Il réserve plus d'espace que nécessaire pour rendre l'insertion plus rapide. réserve vous permet de spécifier cette capacité, tandis que redimensionner modifie la taille réelle du vecteur.

0

Votre dest a alloué de la mémoire pour stocker des éléments après avoir appelé reserve, mais il n'appelle pas de constructeur et il est réellement vide, donc votre code conduit à UB. Utilisez resize pour créer ces éléments et tout ira bien.

dest.resize(src.size()); 
std::copy_n(src.cbegin(), src.size(), dest.begin()); 

std::cout << "src.size() = " << src.size() << std::endl; 
std::cout << "dest.size() = " << dest.size() << std::endl; 

for(size_t i = 0; i < src.size(); ++i) 
    std::cout << dest[i] << " "; 
2

L'essentiel à retenir sur les algorithmes de la bibliothèque standard est qu'ils fonctionnent sur gammes, pas de conteneurs. Les conteneurs sont l'une des façons de créer des plages, mais ce n'est pas la seule. Les algorithmes qui écrivent les résultats dans une plage supposent qu'ils écrivent dans des emplacements valides. ils ne peuvent pas, et ne peuvent pas, étendre la gamme à laquelle ils écrivent. Par conséquent, lorsque vous appelez le std::copy_n, vous devez indiquer une plage suffisamment grande pour contenir le résultat. Cela signifie que vous devez configurer la plage avec dest.resize(src.size());, et pas seulement la mémoire avec dest.reserve(std.size());.

Vous pouvez également fournir une plage qui sait qu'elle est attachée à un conteneur et doit ajuster la taille en appelant l'algorithme avec std::back_inserter(dest) au lieu de dest.begin().