J'ai besoin de copier std::set
à std::vector
:
std::set <double> input;
input.insert(5);
input.insert(6);
std::vector <double> output;
std::copy(input.begin(), input.end(), output.begin()); //Error: Vector iterator not dereferencable
Où est le problème?
Vous devez utiliser un back_inserter
:
std::copy(input.begin(), input.end(), std::back_inserter(output));
std::copy
n'ajoute pas d'éléments au conteneur dans lequel vous insérez: il ne le peut pas; il n'y a qu'un itérateur dans le conteneur. De ce fait, si vous passez un itérateur de sortie directement à std::copy
, vous devez vous assurer qu'il pointe vers une plage suffisamment large pour contenir la plage d'entrée.
std::back_inserter
crée un itérateur en sortie qui appelle Push_back
sur un conteneur pour chaque élément, chaque élément est donc inséré dans le conteneur. Sinon, vous auriez pu créer un nombre suffisant d'éléments dans le std::vector
pour contenir la plage en cours de copie:
std::vector<double> output(input.size());
std::copy(input.begin(), input.end(), output.begin());
Ou, vous pouvez utiliser le std::vector
constructeur de la plage:
std::vector<double> output(input.begin(), input.end());
Il suffit d'utiliser le constructeur pour le vecteur qui prend des itérateurs:
std::set<T> s;
//...
std::vector v( s.begin(), s.end() );
Supposons que vous souhaitiez simplement le contenu de s dans v et qu'il n'y ait rien dans v avant de copier les données sur celui-ci.
voici une autre alternative en utilisant vector::assign
:
theVector.assign(theSet.begin(), theSet.end());
Vous n'avez pas réservé suffisamment d'espace dans votre objet vectoriel pour contenir le contenu de votre ensemble.
std::vector<double> output(input.size());
std::copy(input.begin(), input.end(), output.begin());
std::copy
ne peut pas être utilisé pour insérer dans un conteneur vide. Pour ce faire, vous devez utiliser un insert_iterator comme ceci:
std::set<double> input;
input.insert(5);
input.insert(6);
std::vector<double> output;
std::copy(input.begin(), input.end(), inserter(output, output.begin()));
Je pense que le moyen le plus efficace est de préallouer puis d’emplacer des éléments:
template <typename T>
std::vector<T> VectorFromSet(const std::set<T>& from)
{
std::vector<T> to;
to.reserve(from.size());
for (auto const& value : from)
to.emplace_back(value);
return to;
}
De cette façon, nous n'invoquerons le constructeur de copie pour chaque élément, par opposition à l'appel du constructeur par défaut, puis l'opérateur de copie pour les autres solutions répertoriées ci-dessus. Plus de précisions ci-dessous.
back_inserter peut être utilisé mais il invoquera Push_back () sur le vecteur ( https://en.cppreference.com/w/cpp/iterator/back_insert_iterator ). emplace_back () est plus efficace car il évite de créer un temporaire lorsque vous utilisez Push_back () . Ce n'est pas un problème avec les types construits trivialement, mais sera une implication de performance pour les types non construits trivialement (par exemple, std :: string).
Nous devons éviter de construire un vecteur avec l'argument de taille qui provoque la construction de tous les éléments par défaut (pour rien). Comme avec une solution utilisant std :: copy () , par exemple.
Et, enfin, la méthode vector :: assign () ou le constructeur prenant la plage d'itérateurs ne sont pas de bonnes options car elles invoqueront std :: distance () (connaître le nombre d'éléments) sur définir itérateurs. Cela provoquera une itération supplémentaire indésirable par le biais de tous les éléments set , car il s'agit d'une structure de données d'arborescence de recherche binaire et il n'implémente pas les itérateurs à accès aléatoire.
J'espère que ça t'as aidé.