Question

I usually use a boost::scoped_ptr for pimpl's (for one reason because then I don't get surprises if I forget to deal with the copy constructor)

With templates however I can't just put the destructor in the cpp file where the impl is fully defined in order to fulfill the requirements of scoped_ptr's destructor. It does work anyway but I'm not sure if its garanteed to work or just by chance. Is there some 'best practice' or standard? Is scoped_ptr the best smart pointer for pimpls in non-copyable classes?

template <class T> class C {
public:
    C(){}
    ~C(){}
private:
    boost::scoped_ptr<T> pimpl_;
};
Was it helpful?

Solution

boost::shared_ptr doesn't require a complete definition other than at the point of instantiation—in the constructor, in the case of a pimpl. boost::shared_ptr is not appropriate for the pimpl idiom, however, since it gives very unexpected semantics (reference semantics for assignment or copy); if you really want the added complexity of a smart pointer, boost::scoped_ptr would be more appropirate (but it does require a full definition at the point its destructor is instantiated).

With regards to templates, it makes no sense to use the pimpl idiom for the implementation details from the header. In the absense of export, all of the implementation details of a class template must be included everywhere the template is used, so the motivation behind the pimpl idiom ceases to exist.

OTHER TIPS

It just happens that Herb Sutter started to write his GotWs again after a long time. One of the first new ones are related to "Compilation Firewalls".

You might want to take a look at:

GotW #100: Compilation Firewalls (Difficulty: 6/10)

and

GotW #101: Compilation Firewalls, Part 2 (Difficulty: 8/10)

Two years later I understand the situation much better, in the interest of keeping stack overflow answers relevant and up to date here is how I would answer the question today.

The premise of my original question is somewhat flawed. The reason to use the pimpl-idiom is to hide implementation details from the compiler. This is done by storing the implementation via an opaque pointer (pointer to a declared but not defined data type). This can greatly reduce the amount of headers needed by other compilation units which interact with the class and thus speed up compile time. In the case of the template in my question it is required that the type T be fully known at the point of instantiation which in practice requires the the impl's type be fully defined wherever C<ImplType> is used making this clearly not an example of the pimpl-idiom in the classic sense of the term.

There are other reasons to hold a classes data via a private pointer, for example it allows for easy implementation of no-throw move and swap and is also good if your class needs to fulfill a strong exception guarantee (see copy and swap idiom What is the copy-and-swap idiom?). On the other hand it adds a layer of indirection (often resulting in a cache miss) on every access to the impl and a heap allocation/deallocation upon creation and destruction of the impl. These can be substantial performance penalties, therefore this solution should not be considered a silver bullet.

If you can use C++11 then std::unique_ptr should be used instead of boost::scoped_ptr.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top