171 Stimmen

C++, Kopiersatz auf Vektor

Ich muss kopieren 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

Wo liegt das Problem?

245voto

James McNellis Punkte 337231

Sie müssen eine back_inserter :

std::copy(input.begin(), input.end(), std::back_inserter(output));

std::copy fügt dem Container, in den Sie einfügen, keine Elemente hinzu: Das kann es nicht; es hat nur einen Iterator in den Container. Wenn Sie daher einen Ausgabe-Iterator direkt an std::copy müssen Sie sicherstellen, dass er auf einen Bereich verweist, der mindestens groß genug ist, um den Eingabebereich aufzunehmen.

std::back_inserter erzeugt einen Ausgabe-Iterator, der die push_back auf einen Container für jedes Element, so dass jedes Element in den Container eingefügt wird. Alternativ könnten Sie auch eine ausreichende Anzahl von Elementen in der std::vector um den zu kopierenden Bereich zu halten:

std::vector<double> output(input.size());
std::copy(input.begin(), input.end(), output.begin());

Oder Sie können die Funktion std::vector Bereichskonstruktor:

std::vector<double> output(input.begin(), input.end());

152voto

Jacob Punkte 3451

Verwenden Sie einfach den Konstruktor für den Vektor, der Iteratoren annimmt:

std::set<T> s;

//...

std::vector v( s.begin(), s.end() );

Es wird davon ausgegangen, dass Sie nur den Inhalt von s in v haben wollen und dass sich vor dem Kopieren der Daten in v nichts befindet.

53voto

TeddyC Punkte 583

Hier ist eine weitere Alternative mit vector::assign :

theVector.assign(theSet.begin(), theSet.end());

27voto

Marlon Punkte 19311

Sie haben nicht genügend Platz in Ihrem Vektorobjekt reserviert, um den Inhalt Ihres Sets aufzunehmen.

std::vector<double> output(input.size());
std::copy(input.begin(), input.end(), output.begin());

4voto

dshvets1 Punkte 109

Ich denke, der effizienteste Weg ist es, Elemente vorab zuzuordnen und dann zu platzieren:

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

Auf diese Weise wird nur der Kopierkonstruktor für jedes Element aufgerufen, im Gegensatz zum ersten Aufruf des Standardkonstruktors und dem anschließenden Kopierzuweisungsoperator für die anderen oben aufgeführten Lösungen. Mehr Klarstellungen unten.

  1. rück_inserter kann verwendet werden, ruft aber push_back() für den Vektor auf ( https://en.cppreference.com/w/cpp/iterator/back_insert_iterator ). zurück_stellen() ist effizienter, weil es die Erstellung eines Temporärs vermeidet, wenn man push_back() . Es handelt sich nicht um ein Problem mit trivialen konstruierten Typen, aber es ist eine Leistungseinbuße für nicht trivial konstruierte Typen (z. B. std::string).

  2. Wir müssen vermeiden, einen Vektor mit dem Argument Größe zu konstruieren, der dazu führt, dass alle Elemente standardmäßig (umsonst) konstruiert werden. Wie bei der Lösung mit std::copy() zum Beispiel.

  3. Und schließlich, vector::assign() Methode oder der Konstruktor, der den Iteratorbereich übernimmt, sind keine guten Optionen denn sie rufen std::distance() auf (um die Anzahl der Elemente zu ermitteln) auf einstellen. Iteratoren. Dies führt zu unerwünschten zusätzlichen Iterationen durch alle einstellen. Elemente, da die Menge Binary Search Tree ist Datenstruktur ist und keine Iteratoren mit wahlfreiem Zugriff implementiert.

Ich hoffe, das hilft.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X