Curious
Curious

Reputation: 21510

Template instantiations and pimpl idiom with unique_ptr

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

Answers (2)

R Sahu
R Sahu

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:

  • Copy constructor
  • Move constructor
  • Copy assignment operator
  • Move assignment operator.

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 the unique_ptr<Impl>, and at that point. It will instantiate the template unique_ptr with Impl.

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

Abdus Khazi
Abdus Khazi

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

Related Questions