2014-02-12 7 views
17

Ist es möglich, den Inhalt einer temporären std :: map temp in eine andere std :: map m einzufügen, indem Sie die move-Semantik verwenden, so dass die Werte aus dem temporären nicht kopiert und wiederverwendet werden?Kann ich den Inhalt einer Std :: Map in eine andere Std :: Map verschieben?

Lassen Sie uns sagen, man hat:

std::map<int, Data> temp; 
std::map<int, Data> m; 

Eine Möglichkeit des Kopierens Werte von temp in m ist:

m.insert(temp.begin(),temp.end()); 

Wie kann ich die temp Elemente in m, anstelle des Kopierens bewegen ?

Antwort

17

TIPP:Lesen Sie zuerst das Update!

Der aktuelle C++ 11-Standard und der C++ 14-Entwurf bieten keine Memberfunktion zum Aktivieren dieser Funktion. Wie Lavr vorgeschlagen, dass Sie noch

schreiben
m.insert(make_move_iterator(begin(temp)), 
     make_move_iterator(end (temp))); 

, die die Werte aus dem Quellbehälter in den Zielbehälter bewegt. Es werden jedoch weder die Container-Knoten noch die Schlüssel verschoben. Dies erfordert Speicherzuweisungen (zumindest für die Erstellung der neuen Knoten in der Zielkarte). Die Anzahl der Elemente im Quellcontainer bleibt gleich. Der Grund für das Kopieren ist einfach: Der Werttyp std::map ist std::pair<const Key,T>. Und das Verschieben von einem const Key ist im Wesentlichen Kopieren des Schlüssels (es sei denn, jemand überlastet den Key Konstruktor, der eine const Key &&, für die ich keinen angemessenen Grund denke).

Wenn Sie Daten von einem Container in einen anderen verschieben müssen, können Sie die Verwendung von std::list anstelle von std::map in Erwägung ziehen. Es hat eine member function splice, die die Elemente in konstanter Zeit von einer Liste zu einer anderen verschiebt.

UPDATE:

Da C++ 17 gibt es die Funktion std::map::merge() die im Grunde alle die Elemente einer std::map in eine andere std::map die tatsächlichen Elemente ohne Verschieben oder Kopieren bringt, sondern durch interne Zeiger nur repointing. Es ist sehr ähnlich zu std::list::splice(), die seit C++ 98 existiert.

So können Sie

m.merge(temp); 

schreiben Ihr Ziel zu erreichen. Dies ist effizienter als das Kopieren oder Verschieben aller Elemente von einem Container zum anderen.

Aber Vorsicht! Widersprüchliche Schlüssel werden nicht aufgelöst: Bei übereinstimmenden Schlüsseln wird nichts unternommen.

+1

Während "const Key" kopiert wird, wenn das Paar bewegt wird, und während "temp" die gleiche Anzahl von Elementen behält, wird "T" st krank sein bewegt ... also, wenn 'T' eine große Struktur mit Bewegungssemantik wie' std :: vector' ist, macht das noch Sinn, oder? – iavr

+0

@lavr Ja, tatsächlich. –

2

Ich glaube nicht, dass das möglich ist. Bei anderen Containern würde ich den Adapter std::move_iterator vorschlagen, aber das funktioniert nicht, weil der Schlüssel einer Map const ist.

Mit anderen Worten, Sie können Elemente nicht einzeln aus einer Karte heraus verschieben, da dies die Schlüssel ändern könnte, was eine Zuordnung nicht zulässt.

Und es gibt keine Möglichkeit, nur von einer Karte zu einer anderen zu verschieben. Listen unterstützen Spleißen, aber ich fürchte, die Bäume nicht.

+0

Ich nicht ganz verstehen, die zugrunde liegenden Typen '' std :: pair '', warum könnten die Tasten ändern ?, ich extrahieren nur die '' '' mapped_type'' von temp'' und verschiebe es nach '' m''? – Gabriel

+1

Wenn Sie vom Element einer Karte aus verschieben möchten, handelt es sich um eine Verschiebeoperation aus diesem Paar. Aber du kannst dich nicht von etwas bewegen, das konstant ist. –

7

Haben Sie nicht versucht, aber ich denke, std::move_iterator hier helfen sollte:

using it = std::map<int, Data>::iterator; 
using mv = std::move_iterator <it>; 

m.insert(mv(temp.begin()),mv(temp.end())); 
+0

Whewhw .... Danke dafür von meiner Seite - wusste nicht, dass es diese gab ... –

+0

Ich wusste auch nicht :-) – Gabriel

+0

Ich bin mir ziemlich sicher, dass dies aus den oben genannten Gründen nicht funktionieren wird:/Library/Entwickler/CommandLineTools/usr/bin /../ include/C++/v1/Iterator: 959: 14: Fehler: kann nicht gegossen aus L-Wert des Typs 'const value_type' (auch bekannt als 'const std :: __ 1 :: basic_string ' Referenztyp 'Referenz' (auch bekannt als ‚std :: __ 1 :: basic_string &&'); Typen sind nicht kompatibel return static_cast (* __ i)) zu R-Wert; ^ ~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ – rossb83

Verwandte Themen