Is there any reason not to use pimpl to implement move support in C++?

Viewed 150

Obviously, pimpl is not strictly necessary, but if the class is designed the "normal" way, then, it seems that moving is not going to give you the full intended benefit: moving is supposed to be cheap; in particular, it should be much faster than copying; the cost should not "scale up" with the amount of "real" internal data. Ideally, the cost should be O(1).

Obviously, if you use pimpl, you will achieve this speed benefit every time with minimal effort and maximum reliability (thanks to = default). So, is there any reason not to just do pimpl all over the place whenever you want the ability to move an object?

(I'm assuming that you are allowed to use the heap in your application, since that obviously rules out pimpl.)

2 Answers

Moving is cheaper than copying when it matters - for types that themselve are expensive to move, mostly due to internally allocating heap-memory, like std::string or std::vector. Copying a class the has 10 "ints" it relatively cheap anyways, so there is little to be gained by having a faster "move"-operation on that type of class.

While you are right that pimpl would speed up moves in any case, it also introduces a consistent overhead for both creation of the object (by having to allocate the internal "pimpl" object on the heap") as well as usage (by now having an additional indirection for any external call). I personally don't think that is a reason to use pimpl solely for the reason of making moves faster - unless move is the primary bottleneck in your specific use-case.

Personally, I would rather go the other round - if you have a very large object only consisting of "trivial" types that cannot be efficiently moved, and you want the object to be moved fast, then just store the object on the stack (std::unique_ptr). That way, you don't impose the overhead of pimpl on every user of the class, while still gaining the fast move when you need it.

With pimpl, the only class data member is a pointer. Move support is cheap for that case because copying that pointer is cheaper than copying the large data structure it points to.

But the same reasoning would apply if the class had several pointers to large structures. Or a pointer to a large structure and a few small non pointers.

Related