Returning Objects in C++
c++, factory, memory-management
Solution
Depending on your usage, there are a couple of options you could go with here:
Make a copy every time you create an animal:
class AnimalLister
{
public:
Animal getNewAnimal()
{
return Animal();
}
};
int main() {
AnimalLister al;
Animal a1 = al.getNewAnimal();
Animal a2 = al.getNewAnimal();
}
Pros:
- Easy to understand.
- Requires no extra libraries or supporting code.
Cons:
- It requires `Animal` to have a well-behaved copy-constructor.
- It can involve a lot of copying if `Animal` is larg and complex, although return value optimization can alleviate that in many situations.
- Doesn't work if you plan on returning sub-classes derived from `Animal` as they will be sliced down to a plain `Animal`, losing all the extra data in the sub-class.
Return a `shared_ptr<Animal>`:
class AnimalLister
{
public:
shared_ptr<Animal> getNewAnimal()
{
return new Animal();
}
};
int main() {
AnimalLister al;
shared_ptr<Animal> a1 = al.getNewAnimal();
shared_ptr<Animal> a2 = al.getNewAnimal();
}
Pros:
- Works with object-hierarchies (no object slicing).
- No issues with having to copy large objects.
- No need for `Animal` to define a copy constructor.
Cons:
- Requires either Boost or TR1 libraries, or another smart-pointer implementation.
Track all `Animal` allocations in `AnimalLister`
class AnimalLister
{
vector<Animal *> Animals;
public:
Animal *getNewAnimal()
{
Animals.push_back(NULL);
Animals.back() = new Animal();
return Animals.back();
}
~AnimalLister()
{
for(vector<Animal *>::iterator iAnimal = Animals.begin(); iAnimal != Animals.end(); ++iAnimal)
delete *iAnimal;
}
};
int main() {
AnimalLister al;
Animal *a1 = al.getNewAnimal();
Animal *a2 = al.getNewAnimal();
} // All the animals get deleted when al goes out of scope.
Pros:
- Ideal for situations where you need a bunch of `Animal`s for a limited amount of time, and plan to release them all at once.
- Easily adaptable to custom memory-pools and releasing all the `Animal`s in a single `delete`.
- Works with object-hierarchies (no object slicing).
- No issues with having to copy large objects.
- No need for `Animal` to define a copy constructor.
- No need for external libraries.
Cons:
- The implementation as written above is not thread-safe
- Requires extra support code
- Less clear than the previous two schemes
- It's non-obvious that when the AnimalLister goes out of scope, it's going to take the Animals with it. You can't hang on to the Animals any longer than you hang on the AnimalLister.
Problem
When returning objects from a class, when is the right time to release the memory? Example, ``` class AnimalLister { public: Animal* getNewAnimal() { Animal* animal1 = new Animal(); return animal1; } } ``` If i create an instance of Animal Lister and get Animal reference from it, then where am i supposed to delete it? ``` int main() { AnimalLister al; Animal *a1, *a2; a1 = al.getNewAnimal(); a2 = al.getNewAnimal(); } ``` The problem here is AnimalLister doesnot have a way to track the list of Animals Created, so how do i change the logic of such code to have a way to delete the objects created.