Let's assume we have something like this:
Complex(Part1 p1, Part2 p2, Part3 p3)
p1, p2, p3
The best solution would be to make the
Part types cheap to move, and move them in. However, if that is not an option, you will have to resort to managing them dynamically.
As you say,
Complex owns the parts, so it should accept them as
std::uniqe_ptr<Part> and move these pointers into itself. Moving a
std::unique_ptr is dirt cheap: it probably involes just two pointer assignments.
On the other hand, using
std::shared_ptr and copying that involves an unnecessary atomic increment (for creating the copy) and decrement (for destroying the original). Atomic operations are certainly far from cheap for today's cache-heavy, multi-core processors.
So just stick to the intended semantics of your code (unique ownership, which is idiomatically expressed by
std::unique_ptr), and you will get good performance as a bonus.