Reputation: 21510
I read this answer by Howard Hinnant (Is std::unique_ptr<T> required to know the full definition of T?) and then this answer (How is a template instantiated?) and I was just thinking. If you have a class like so
class Something {
Something();
~Something();
class Impl;
std::unique_ptr<Impl> impl;
};
The unique_ptr
will be instantiated at that point when the class is compiled (as I could make out from the other answer above). Then why is it okay to not have the class Impl
defined later on? Won't the instantiation require the destructor of Impl
to be present?
Note The following is in an effort to clarify what I am asking above.
The way I am thinking about it, when the compiler goes over the definition of the class Something
. It will see the declaration of the nested class Impl
and then it will see the declaration of the unique_ptr<Impl>
, and at that point. It will instantiate the template unique_ptr
with Impl
. And that instantiated code will contain a call to the destructor of Impl
. Since at this point we have code that includes a call to the destructor of an incomplete class, how is the code above safe?
Upvotes: 2
Views: 340
Reputation: 206567
The accepted answer to the first question contains a table of use cases where the complete definition of Impl
is required.
In your case, the compiler implicitly generates the following member functions:
All of them require the complete definition of Impl
.
If you explicitly declare those functions and define them where the complete definition of Impl
is available, you'll be OK.
Update
It will see the declaration of the nested class
Impl
and then it will see the declaration of theunique_ptr<Impl>
, and at that point. It will instantiate the templateunique_ptr
withImpl
.
That is correct only to an extent. Not all member functions of unique_ptr
will be instantiated at that time.
And that instantiated code will contain a call to the destructor of
Impl
.
Not correct. The compiler will generate the code (or instantiate) the destructor of std::unique_ptr<Impl>
only when it is needed. That place is the destructor of Something
.
Destructor of Something
will need destructor of std::unique_ptr<Impl>
.
Destructor of std::unique_ptr<Impl>
needs the complete definition of Impl
.
In other words, the complete definition of Impl
must be visible to the destructor of Something
.
PS
More on template instantiation can be found at Template instantiation details of GCC and MS compilers.
Upvotes: 1
Reputation: 473
If you write try to compile the above code and create an object of Something, it will give an error message :
Semantic issue:
memory:2523:27: Invalid application of 'sizeof' to an incomplete type
'Something::Impl'
In short the code is uncompilable and there is no point of taking about safety in this case.
Upvotes: 0