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> head
instancji, 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_ptr
destruktor w node
, a następnie użyje rekurencji ogona), co staje się znacznie trudniejsze, jeśli wykonam następujące czynności (ponieważ data
destruktor 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 data
jakiś sposób ma do niego wskaźnik, node
wó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 -O3
nie było w stanie zoptymalizować rekurencji ogona (w skomplikowanym przykładzie).