I wrote this article and got some comments on it that confused me.
It basically boils down to my having seen T2 used only as a template parameter and mistakenly jumped to the conclusion that I could therefore take the opportunity of forward declaration:
struct T2;
struct T1
{
std::auto_ptr<T2> obj;
};
This invokes UB if I don't go on to define T2 somewhere in the same TU, because std::auto_ptr<T2> calls delete on its internal T2*, and calling delete on an pointer to an object of an incomplete type whose complete type has a non-trivial destructor is undefined:
[C++11: 5.3.5/5]:If the object being deleted has incomplete class type at the point of deletion and the complete class has a non-trivial destructor or a deallocation function, the behavior is undefined.
The GCC toolchain I happened to be using — v4.3.3 (Sourcery G++ Lite 2009q1-203) — was kind enough to let me know with a note:
note: neither the destructor nor the class-specific operator delete will be called, even if they are declared when the class is defined.
though it seems difficult to get this diagnostic in other GCC versions.
My gripe was that it would be a lot easier to spot a bug like this if deleteing a pointer to an instance of an incomplete type were ill-formed rather than UB, but that seems like an intractible problem for an implementation to solve, so I understand why it's UB.
But then I'm told that, if I were to use std::unique_ptr<T2> instead, this would be safe and compliant.
n3035 allegedly says at 20.9.10.2:
The template parameter
Tofunique_ptrmay be an incomplete type.
All I can find in C++11 proper is:
[C++11: 20.7.1.1.1]:/1 The class template
default_deleteserves as the default deleter (destruction policy) for the class templateunique_ptr./2 The template parameter
Tofdefault_deletemay be an incomplete type.
But, default_delete's operator() does require a complete type:
[C++11: 20.7.1.1.2/4]:IfTis an incomplete type, the program is ill-formed.
I suppose my question is this:
Are the commenters on my article correct in saying that a translation unit consisting of only the following code is well-formed and well-defined? Or are they wrong?
struct T2;
struct T1
{
std::unique_ptr<T2> obj;
};
If they are correct, how is a compiler expected to implement this, given that there are good reasons for it being UB, at least when an std::auto_ptr is used?