Consider this code, with an obvious compile error: (1)
struct A;
struct B {
B() { new A(); } // error: allocation of incomplete type 'A'
};
Using a unique_ptr
will not help either: (2)
struct A;
struct B {
B() { std::make_unique<A>(); } // error: due to ~unique_ptr()
};
Then (to my great surprise) I found out, that this will compile: (3)
struct A;
struct B {
B() { std::make_unique<A>(); }
};
struct A {}; // OK, when a definition is added **below**
Then I checked, whether this helps with new
as well - nope: (4)
struct A;
struct B {
B() { new A(); } // error: allocation of incomplete type 'A'
};
struct A {};
I figured it has something to do with template
s and in fact: wrapping new
inside a template
does compile: (5)
template <typename T>
T* my_new() { return new T(); } // OK, when wrapped in template
struct A;
struct B {
B() { my_new<A>(); }
};
struct A {};
And just for the sake of completeness, removing the definition of A
raises an error again: (6)
template <typename T>
T* my_new() { return new T(); } // error: allocation of incomplete type 'A'
struct A;
struct B {
B() { my_new<A>(); }
};
// do note: definition of A removed
What's going on here? As far as I understood, the compiler must know the size/definition of A
to allocate it, thus merely declaring it, is not sufficient. In addition I believed, that the definition must precede the allocation.
This seems to be correct, when using new
directly (1,4). But when new
is wrapped, it is apparent that I am mistaken (2,3,5,6).
Possible explanations I found so far are:
- The check for completed types is delayed until the
template
instantiation occurs. I think this is correct, but in my case the direct use of new A()
and the call to my_new<A>()
occur virtually on the same position. So this cannot be the reason. Right?
- Using incomplete types as
template
Arguments might be undefined behavior. Is this really true? Even when enabling all warnings, the compiler will not complain. Also comparing 5 and 6 seems to suggest, that the compiler is smart enough to figure out, that the definition follows below (thus virtually making the type complete).
Why 4 is considered to be incorrect, whilst 5 compiles (or is 5 just spuriously compiling undefined behavior [but then 3 must be flawed as well, right?])?
btw: tested with clang++-3.5.0 and g++-4.9.2
See Question&Answers more detail:
os