The Pimpl Idiom in practice

2019-01-07 04:10发布

There have been a few questions on SO about the pimpl idiom, but I'm more curious about how often it is leveraged in practice.

I understand there are some trade-offs between performance and encapsulation, plus some debugging annoyances due to the extra redirection.

With that, is this something that should be adopted on a per-class, or an all-or-nothing basis? Is this a best-practice or personal preference?

I realize that's somewhat subjective, so let me list my top priorities:

  • Code clarity
  • Code maintainability
  • Performance

I always assume that I will need to expose my code as a library at some point, so that's also a consideration.

EDIT: Any other options to accomplish the same thing would be welcome suggestions.

8条回答
劳资没心,怎么记你
2楼-- · 2019-01-07 04:34

pImpl will work best when we have r-value semantics.

The "alternative" to pImpl, that will also achieve hiding the implementation detail, is to use an abstract base class and put the implementation in a derived class. Users call some kind of "factory" method to create the instance and will generally use a pointer (probably a shared one) to the abstract class.

The rationale behind pImpl instead can be:

  • Saving on a v-table. Yes, but will your compiler inline all the forwarding and will you really save anything.
  • If your module contains multiple classes that know about each other in detail although to the outside world you hide that.

Semantics of the container class for the pImpl could be: - Non-copyable, not assignable... So you "new" your pImpl on construction and "delete" on destruction - shared. So you have shared_ptr rather than Impl*

With shared_ptr you can use a forward declaration as long as the class is complete at the point of the destructor. Your destructor should be defined even if default (which it probably will be).

  • swappable. You can implement "may be empty" and implements "swap". Users can create an instance of one and pass a non-const reference to it to get it populated, with a "swap".

  • 2-stage construction. You construct an empty one then call "load()" on it to populate it.

shared is the only one I have even a remote liking for without r-value semantics. With them we can also implement non-copyable non-assignable properly. I like to be able to call a function that gives me one.

I have, however, found I tend more now to use abstract base classes more than pImpl, even when there is only one implementation.

查看更多
Summer. ? 凉城
3楼-- · 2019-01-07 04:42

This idiom helps greatly with compile time on large projects.

External link

This is good too

查看更多
登录 后发表回答