Ich fand heraus, dass ein Element aus einer Menge aus einer anderen Menge gelöscht werden kann, indem die Erase-Methode verwendet wird, die einen Iterator akzeptiert. Ich kann nicht erklären, warum das passiert, und ich würde gerne wissen, ob das normal ist oder nicht.Löschen von Elementen aus einer Gruppe durch Aufrufen von Erase (Iterator) auf einer anderen Gruppe. Ist das normales Verhalten?
So läßt die Szene:
Ich habe eine Reihe von Objekten, die ich in zwei STL-Sets getrennt, aus logischen Gründen (das heißt, sie sind disjunkte Mengen).
std::set<Obj> set_a;
std::set<Obj> set_b;
Die set_a enthält die Objekte, die ich möchte. Wenn dieses Objekt nicht in set_a gefunden wird, wird ein leeres Objekt erstellt und in set_b eingefügt. Ich führe dann einige Berechnungen für das gewünschte Objekt durch, und wenn eine bestimmte Bedingung erfüllt ist, lösche ich es.
std::set<Obj>::iterator it = set_a.find(o);
std::set<Obj>::iterator end = set_a.end();
if (it == end) {
it = set_b.lower_bound();
end = set_b.end();
if (it == end || *it != o) {
it = set_b.insert(it, o);
}
}
// do calculations with it
if (/*condition is met*/) {
// erase it
}
Also fragte ich mich, wie ich dieses Objekt löschen würde. Da ich den Iterator habe, dachte ich daran, ihn direkt zu löschen. Was passiert aber, wenn Sie Erase mit einem Iterator verwenden, der auf ein Objekt in einem anderen Set "zeigt"? Es gibt nichts in der Dokumentation, die ich verwende (http://www.cplusplus.com/reference/stl/set/erase/), also habe ich den folgenden Test gemacht.
#include <iostream>
#include <iterator>
#include <algorithm>
#include <set>
#include <sstream>
// streams
using std::cout;
using std::ostream_iterator;
using std::ostringstream;
// data structures
using std::set;
// algorithms
using std::copy;
int main() {
set<int> s, s2;
s.insert(1);
s.insert(2);
s.insert(4);
cout << "Initial set\n";
// print set elements
copy(s.begin(), s.end(), ostream_iterator<int> (cout, " "));
cout << "\n";
set<int>::iterator s_it = s.lower_bound(3);
if (s_it == s.end() || *s_it != 3) {
s_it = s.insert(s_it, 3);
}
cout << "Set after insertion\n";
// print set elements
copy(s.begin(), s.end(), ostream_iterator<int> (cout, " "));
cout << "\n";
// erase element from another set
s2.erase(s_it);
cout << "Set after erasure\n";
// print set elements
copy(s.begin(), s.end(), ostream_iterator<int> (cout, " "));
cout << "\n";
return 0;
}
Dieser Test ergibt folgende Ausfahrt:
Initial set 1 2 4 Set after insertion 1 2 3 4 Set after erasure 1 2 4
Ich fand es sehr merkwürdig, dass ein Element von s durch den Aufruf der Methode von s2 gelöscht werden konnte, so ausgeführt ich mein Programm mit Valgrind. Keine Fehler dort. Ich denke, dass ich von diesem Verhalten tatsächlich profitieren würde, da ich nicht überprüfen muss, welcher Satz das Element enthält, aber ich frage mich, ob das normales Verhalten ist oder nicht.
Danke!
Ich bin mir nicht sicher, welche Schlussfolgerung Sie zeichnen. Sie setzen das Element in s und löschten es aus s, indem Sie einen Iterator verwenden, der auf das Element in s verweist. s2 hatte wirklich nichts mit irgendetwas zu tun. –
@Anon, sagst du, dass der Aufruf von s2.erase() mit einem Iterator auf s funktioniert, vorausgesetzt, dass s und s2 vom selben Typ sind? –
@Tony: Ich sage das nicht. Ich sage nur, dass "das Löschen eines Elements in A von einem Iterator in B" überhaupt nicht das ist, was hier passiert. –