Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Returning Objects in C++

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.

like image 505
bibstha Avatar asked Oct 15 '08 11:10

bibstha


People also ask

What is a returning object?

When an object is returned by value from a function, a temporary object is created within the function, which holds the return value. This value is further assigned to another object in the calling function. The syntax for defining a function that returns an object by value is. 1.

What is returning object in C Plus Plus?

An object is an instance of a class. Memory is only allocated when an object is created and not when a class is defined. An object can be returned by a function using the return keyword. A program that demonstrates this is given as follows −

How do you return a class object?

If a method or function returns an object of a class for which there is no public copy constructor, such as ostream class, it must return a reference to an object. Some methods and functions, such as the overloaded assignment operator, can return either an object or a reference to an object.


2 Answers

Depending on your usage, there are a couple of options you could go with here:

  1. 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.
  2. 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.
  3. 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 Animals for a limited amount of time, and plan to release them all at once.
    • Easily adaptable to custom memory-pools and releasing all the Animals 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.
like image 171
Eclipse Avatar answered Sep 20 '22 12:09

Eclipse


I advise returning a std::tr1::shared_ptr (or boost::shared_ptr, if your C++ implementation does not have TR1) instead of a raw pointer. So, instead of using Animal*, use std::tr1::shared_ptr<Animal> instead.

Shared pointers handle reference tracking for you, and delete the object automatically if there are no references left to it.

like image 23
Chris Jester-Young Avatar answered Sep 22 '22 12:09

Chris Jester-Young