29 votes

Existe-t-il un moyen standard de déplacer une plage dans un vecteur?

Considérons le programme suivant, qui insère un éventail d'éléments dans un vecteur:

vector<string> v1;
vector<string> v2;

v1.push_back("one");
v1.push_back("two");
v1.push_back("three");

v2.push_back("four");
v2.push_back("five");
v2.push_back("six");

v1.insert(v1.end(), v2.begin(), v2.end());

Cette efficacité des copies de la gamme, d'allouer suffisamment d'espace dans la cible de vecteur pour l'ensemble de la gamme ainsi qu'un maximum d'un redimensionnement sera nécessaire. Maintenant, considérons le programme suivant qui tente de déplacer une plage dans un vecteur:

vector<string> v1;
vector<string> v2;

v1.push_back("one");
v1.push_back("two");
v1.push_back("three");

v2.push_back("four");
v2.push_back("five");
v2.push_back("six");

for_each ( v2.begin(), v2.end(), [&v1]( string & s )
{
    v1.emplace_back(std::move(s));
});

Ce rapport effectue un déménagement réussi, mais ne pas profiter des avantages que l'insert() à l'égard des preallocating de l'espace dans la cible vecteur, le vecteur peut être redimensionnée à plusieurs reprises au cours de l'opération.

Donc ma question est, est-il un insert équivalent qui peuvent se déplacer d'une plage dans un vecteur?

46voto

Steve Jessop Points 166970

Vous utilisez un move_iterator avec insert:

v1.insert(v1.end(), make_move_iterator(v2.begin()), make_move_iterator(v2.end()));

L'exemple de la 24.5.3 est presque exactement cela.

Vous aurez l'optimisation que vous voulez si (un) vector::insert utilise un itérateur-étiquette d'expédition pour détecter les accès aléatoire itérateur et précalculer la taille (ce que vous avez supposé qu'il fait dans votre exemple que des copies), et (b) move_iterator préserve l'itérateur de la catégorie de l'itérateur elle enveloppe (qui est requis par la norme).

Sur un point obscur: je suis assez sûr qu' vector::insert peut emplace à partir de la source (qui n'est pas pertinent ici, puisque la source est du même type que la destination, de sorte qu'un emplace est la même chose qu'un copier/déplacer, mais il serait pertinent sinon identique les exemples). Je n'ai pas encore trouvé une déclaration qu'il est tenu de le faire, j'ai juste déduit du fait que l'exigence sur l'itérateur paire i,j passée de insert que T être EmplaceConstructible de *i.

24voto

sehe Points 123151
  1. std::move algorithme avec préallocation:

     #include <iterator>
    #include <algorithm>
    
    v1.reserve(v1.size() + v2.size()); // optional
    std::move(v2.begin(), v2.end(), std::back_inserter(v1));
     
  2. Les éléments suivants seraient encore plus flexibles:

     v1.insert(v1.end(), 
         std::make_move_iterator(v2.begin()), 
         std::make_move_iterator(v2.end()));
     

    Steve Jessop a fourni des informations générales sur ce qu'il fait et probablement comment il le fait.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X