Rozważ następującą pojedynczo połączoną implementację listy:
struct node {
std::unique_ptr<node> next;
ComplicatedDestructorClass data;
}
Załóżmy teraz, że przestałem używać std::unique_ptr<node> headinstancji, która następnie wykracza poza zakres, powodując wywołanie jej destruktora.
Czy to zniszczy mój stos na wystarczająco duże listy? Czy można założyć, że kompilator wykona dość skomplikowaną optymalizację (wbudowany unique_ptrdestruktor w node, a następnie użyje rekurencji ogona), co staje się znacznie trudniejsze, jeśli wykonam następujące czynności (ponieważ datadestruktor zaciemniłby next, co utrudnia aby kompilator zauważył potencjalną możliwość ponownego zamawiania i możliwość wywołania ogona):
struct node {
std::shared_ptr<node> next;
ComplicatedDestructorClass data;
}
Jeśli w datajakiś sposób ma do niego wskaźnik, nodewówczas rekurencja ogona może być nawet niemożliwa (choć oczywiście powinniśmy starać się unikać takich naruszeń hermetyzacji).
Ogólnie więc, w jaki sposób należy zniszczyć tę listę w inny sposób? Nie możemy przechodzić przez listę i usuwać „bieżącego” węzła, ponieważ wspólny wskaźnik nie ma release! Jedynym sposobem jest niestandardowy deleter, który jest dla mnie naprawdę śmierdzący.
gcc -O3nie było w stanie zoptymalizować rekurencji ogona (w skomplikowanym przykładzie).