Betrachten Sie die folgende Implementierung einer einzeln verknüpften Liste:
struct node {
std::unique_ptr<node> next;
ComplicatedDestructorClass data;
}
Angenommen, ich verwende std::unique_ptr<node> head
keine Instanz mehr, die dann außerhalb des Gültigkeitsbereichs liegt und deren Destruktor aufgerufen wird.
Wird dies meinen Stapel für ausreichend große Listen sprengen? Ist es fair anzunehmen, dass der Compiler eine ziemlich komplizierte Optimierung durchführt (Inline unique_ptr
-Destruktor in node
's, dann Schwanzrekursion verwenden), die viel schwieriger wird, wenn ich Folgendes tue (da der data
Destruktor die verschleiern würde next
, was es schwierig macht damit der Compiler die potenzielle Neuordnungs- und Tail-Call-Möglichkeit bemerkt):
struct node {
std::shared_ptr<node> next;
ComplicatedDestructorClass data;
}
Wenn es data
irgendwie einen Zeiger node
darauf gibt, kann es sogar unmöglich sein, den Schwanz zu rekursieren (obwohl wir uns natürlich bemühen sollten, solche Verstöße gegen die Kapselung zu vermeiden).
Wie soll man diese Liste dann im Allgemeinen sonst zerstören? Wir können die Liste nicht durchlaufen und den "aktuellen" Knoten löschen, da der gemeinsam genutzte Zeiger kein release
! Der einzige Weg ist mit einem benutzerdefinierten Deleter, der für mich wirklich stinkt.
gcc -O3
nicht möglich, eine Schwanzrekursion zu optimieren (in einem komplizierten Beispiel).