Lets say I have a class Obj
, and instances of them are created at run time, can I store them without new
like this?
Obj my_obj;
std::vector<Obj> my_vec;
my_vec.push_back(my_obj);
Or do I have to use new?
std::vector<Obj*> my_vec;
my_vec.push_back(new Obj);
And what if I have pointers inside of my class Obj
? Also, what if use the second option, do I have to clean up everything?
CodePudding user response:
The question is related to heap allocated objects vs. stack objects. There are already a few good resources on that in Stackoverflow:
- Stack Memory vs Heap Memory
- Stack vs Heap C
- C stack vs heap allocation
- Why should I use a pointer rather than the object itself?
(you may want to look at all the above, each has its own angle).
But, your question is specifically about a container holding objects or pointers to objects. For this there are a few other resources:
- Should I store entire objects, or pointers to objects in containers?
- Is it better to save object pointer in STL container rather than object itself?
Let me summarize shortly:
Usually working with values and not pointers should be your preferred option. They are much easier to maintain and less bug-prone. Before C 11 performance considerations could be a reason for considering working with container of pointers, but since move semantics came in C 11, if you design your code properly, working with containers of values should not be costly.
Another reason for working with pointers might be polymorphism. You want your container to hold and manage different types which share the same base class. Though it seems that a container of pointers should be the solution in such a case, which is used in many examples for polymorphism in C , this still should not be your preferred choice. The first alternative for raw pointers should be holding unique_ptr
which is a smart pointer type introduced in the C standard library in C 11.
The other option is to model the data that you want to manage withing a class that would hide and manage your polymorphism without exposing it to the container or to the user. Let's take an example: suppose you want to manage a container of Command objects, where Command is a base class for many different actual commands. Instead of having a container of Command*
or unique_ptr<Command>
, rename Command to be CommandBase, then hold (wrap, hide) unique_ptr<CommandBase>
inside class Command
and hold in your container objects of type Command
.
Another alternative would be to avoid inheritance altogether. So for different callables (our Command example) you can just use std::function
.
You can also use std::variant
to manage the different types (e.g. using Shape = std::variant<Circle, Triangle>;
).
Hiding the fact that you are using polymorphism, or avoiding polymorphism altogether, can become quite useful in your API, with the benefits of being able to preserve proper value semantics.
More on value semantics and its benefits can be found in CppCon 2022 talk by Klaus Iglberger: Back to Basics: Cpp Value Semantics and in C Now 2022 talk by Dave Abrahams: A Future of Value Semantics and Generic Programming, Part 1 and Part 2. The original talk on the subject, by Sean Parent: Value Semantics and Concepts-based Polymorphism, from C Now 2012.
You can also read about value semantics in the following links:
- C classes as value types a Microsoft blog post
- Reference and Value Semantics in ISO-CPP FAQ
- Value Semantics and Polymorphism a blog post by Dean Berris