3

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.)

TylerH
  • 20,799
  • 66
  • 75
  • 101
allyourcode
  • 21,871
  • 18
  • 78
  • 106
  • Does "pimpl" in this case include hiding all implementation details in the .cpp file so that the implementation can change without the calling code needing to be recompiled? If so, there are reasons why you might not want to do that; allowing the implementation to be located in the header file means compiler can do inlining operations that wouldn't be possible if it was only in the .cpp file (at the cost of requiring calling code be recompiled if the call-site-visible implementation changes, of course) – Jeremy Friesner May 24 '21 at 05:33
  • Also if cache locality was your primary concern, you might not want your "hot"/often-accessed data to be located all over the place in various dynamic-heap-allocations; better to keep it all inlined together in the same array in order to minimize cache misses. – Jeremy Friesner May 24 '21 at 05:36

2 Answers2

7

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.

Juliean
  • 173
  • 6
0

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.

Raedwald
  • 46,613
  • 43
  • 151
  • 237