Czy to prawda, że deklaracja unique_ptr, w przeciwieństwie do deklaracji auto_ptr, jest dobrze zdefiniowana, gdy jej typ szablonu jest niekompletny?
napisałemTen artykuł i dostałem kilka komentarzy, które mnie zdezorientowały.
Zasadniczo sprowadza się to do tego, że widziałemT2
używany tylko jako parametr szablonu i omyłkowo przeskoczył do wniosku, że mogę zatem skorzystać z możliwości przekazania deklaracji:
struct T2;
struct T1
{
std::auto_ptr<T2> obj;
};
To wywołuje UB, jeśli nie będę definiowaćT2
gdzieś w tej samej TU, ponieważstd::auto_ptr<T2>
połączeniadelete
na swoim wewnętrznymT2*
, ipowołaniedelete
na wskaźniku do obiektu niekompletnego typu, którego typ kompletny ma nietrywialny destruktor, jest niezdefiniowany:
[C++11: 5.3.5/5]:
Jeśli usuwany obiekt ma niekompletny typ klasy w miejscu usunięcia, a pełna klasa ma nietrywialny destruktor lub funkcję zwolnienia, zachowanie jest niezdefiniowane.
Zestaw narzędzi GCC, z którego korzystałem - wersja 4.3.3 (Sourcery G ++ Lite 2009q1-203) - był na tyle uprzejmy, że dał mi znać:
Uwaga: nie zostanie wywołany ani destruktor, ani operator usuwania specyficzny dla klasy, nawet jeśli są zadeklarowane, gdy klasa jest zdefiniowana.
choć wydaje się, że trudno jest uzyskać tę diagnostykę w innych wersjach GCC.
Narzekałem, że o wiele łatwiej byłoby wykryć taki błąd, jeślidelete
Wstawiono wskaźnik do instancji niekompletnego typuźle uformowany zamiast UB, ale wydaje się, że problem jest trudny do rozwiązania, więc rozumiem, dlaczego to jest UB.
Ale wtedy mi to powiedziano, gdybym miał użyćstd::unique_ptr<T2>
zamiast tego byłoby to bezpieczne i zgodne.
n3035 rzekomo mówi o 20.9.10.2:
Parametr szablonuT
zunique_ptr
może być niekompletny.
Wszystko, co mogę znaleźć w C ++ 11, to:
[C++11: 20.7.1.1.1]:
/ 1 Szablon klasydefault_delete
służy jako domyślny deleter (polityka niszczenia) dla szablonu klasyunique_ptr
.
/ 2 Parametr szablonuT
zdefault_delete
może być niekompletny.
Ale,default_delete
jestoperator()
nie wymaga pełnego typu:
[C++11: 20.7.1.1.2/4]:
JeśliT
jest niekompletnym typem, program jest źle sformatowany.
Przypuszczam, że moje pytanie brzmi:
Czy komentatorzy mojego artykułu mają rację mówiąc, że jednostka tłumaczeniowa składająca się tylko z następującego kodu jest dobrze uformowana i dobrze zdefiniowana? Czy oni się mylą?
struct T2;
struct T1
{
std::unique_ptr<T2> obj;
};
Jeśli są poprawne, w jaki sposób kompilator ma to zaimplementować, biorąc pod uwagę, że istnieją dobre powody, dla których jest to UB, przynajmniej wtedy, gdystd::auto_ptr
jest używany?