Ich habe zwei std::map<>
Objekte a
und b
möchte einige Elemente (Knoten) basierend auf einem Prädikat von einer Karte zur anderen verschieben ( extract
+ insert
) p
.
for (auto i = a.begin(); i != a.end(); ++i)
if (p(*i))
b.insert(a.extract(i))
Dieser Code ist in clang fehlerhaft. Ich gehe davon aus, dass das Problem das Inkrement ist, i
nachdem sein Knoten aus a extrahiert wurde.
Ist dies der richtige / einzige Weg, um dies mithilfe eines Post-Inkrements zu beheben? ZB:
for (auto i = a.begin(); i != a.end();)
if (p(*i))
b.insert(a.extract(i++))
else
++i;
BEARBEITEN : Ich habe den Teil über "Warum funktioniert das in gcc?" Entfernt, da ich dies in meinem aktuellen Setup nicht reproduzieren kann. Ich bin überzeugt, dass es irgendwann einmal war, aber mit gcc 9.2.1 bekomme ich einen Deadlock (anstelle eines Segfault). In beiden Fällen extract()
funktioniert das Inkrementieren nach nicht.
std::set
undstd::map
sind sehr ähnlich, und soweit ich das beurteilen kann,extract
hat dies die gleichen Auswirkungen auf die Ungültigmachung wieerase
.Antworten:
Tatsächlich. Die Extraktion macht Iteratoren für das extrahierte Element ungültig und
i
ist ein solcher Iterator. Das Verhalten des Inkrementierens oder Indirektierens durch einen ungültigen Iterator ist undefiniert.Weil das Verhalten des Programms undefiniert ist.
Es ist ein richtiger Weg, dies zu beheben. Es ist kein besonders schlechter Weg. Wenn Sie das Inkrement nicht wiederholen möchten, verwenden Sie eine Variable:
quelle
current
würde in einem verschobenen Zustand belassen. Was auch immer dieser Zustand ist, spielt keine Rolle, da er danach nicht mehr verwendet wird.current
durch die Verwendung der C ++ 17s-if (auto current = ++i; p(*current))
Syntax.