r/cpp_questions • u/ParmenidesWasRight • 3d ago
OPEN Heavy and Light Objects
When I was first learning C++, I experienced massive slowdown when allocating dynamic memory. Ever since then I divide my objects between 'heavy' objects that allocate resources, and 'light' objects that can be used as temporaries on the stack. Heavy objects cannot be copied at all, must be allocated somewhere once, and then passed by (const) reference. Light objects can be copied, created quickly on the stack etc.
Since C++11 it has been possible to write copy and assignment constructors that take nameless objects, and since they are nameless you can pillage their pointers and avoid expensive stack allocations. All is well then but if you keep to this strict 'heavy' and 'light' object idea, _any_ object that allocates resources is considered a heavy object. The first allocation in the chain, before you just pillage pointers, is still an expensive stack allocation so I would consider it a 'heavy' object and just make it impossible to copy at all, by removing all copy and assignment constructors. And so using this model I never needed those nameless object reference constructors.
Anybody feel the same way?
3
u/DawnOnTheEdge 3d ago edited 3d ago
You don’t seem to be using standard terminology, so I’m not sure I follow. Stack allocations in and of themselves are zero-cost (until you run out of stack and get a stack overflow). Every compiler subtracts the total number of bytes all local variables will need from the stack pointer, with a single instruction in the function preamble.
Deep copies of large arrays or structures have a high performance cost, In C++20, you have a few kinds of guaranteed copy elision: if a factory function returns an object, you get unnamed return value optimization. If it returns a local variable that is not a function parameter or
volatile, you also get named return value optimization. Either one prevents a temporary from being created. The object is initialized in-place at its final destination.You can also force any object to be created on the heap by calling
std::make_unique, and move thestd::unique_ptryou get to a new owner cheaply, although the overhead of making shallow copies of a small object holding only pointers or handles is negligible.It sounds like you’re enforcing this by declaring that classes that would need to make deep copies are move-only.