2

So let's say I have a class MyClass. Now I want to use another class called Animals, I would probably do the following.

class MyClass
{
public:
    MyClass();
private:
    Animals animals;
};

However I can also do this:

class MyClass
{
public:
    MyClass();
private:
    Animals* animals;
};

and then initialize the class in the constructor with:

animals = new Animals();

What is the difference between the two different approaches, which is better and why? In my use Animals should only be used inside MyClass. My question is mainly about performance and memory, I mean is initializing by pointer requires more resources or not?

reckless
  • 741
  • 12
  • 53
  • 4
    This sounds like a homework question. Can you specify your question down a little bit – TankorSmash Aug 30 '16 at 16:09
  • 2
    Looks like you need to read [this](http://stackoverflow.com/questions/162941/why-use-pointers) – NathanOliver Aug 30 '16 at 16:10
  • @TankorSmash it's not a homework question, but I will try to improve my question – reckless Aug 30 '16 at 16:12
  • Maybe you could try specifying how you're looking to use animals as a pointer or something, and explain the problem you ran into by doing it that way. Right now its so broad it's hard to answer effectively. – TankorSmash Aug 30 '16 at 16:13
  • Allocating with `new` gives you a pointer to an object created on the heap. The first method pre-allocates memory as part of the parent structure. If you allocate via `new` you *must* free that memory eventually. – tadman Aug 30 '16 at 16:14
  • You should prefer the initialization list of the ctor over the ctor body. – Jesper Juhl Aug 30 '16 at 16:18

3 Answers3

5

If you consider how memory is managed in a class it should become clear. When you declare Animals animal in your class, then space is reserved for animal in the memory footprint of your class. But when you declare Animals* animal only a pointer to Animal is reserved in the memory footprint of your class.

Neither is better, as it depends on your circumstances. If you are always going to create an animal and MyClass owns it, then use the first approach as it will only require one memory allocation. If animals can often be empty and memory is a concern then you might want to use the second approach.

Incidentally if you are using C++11 or above, you might want to consider std::unique_ptr<Animal> for the second case.

keith
  • 5,122
  • 3
  • 21
  • 50
1

If the sole existence of the animals object depend on the MyClass object, then use containment:

class MyClass
{
public:
    MyClass();
private:
    Animals animals;
};

If the existence of animals is independent, but MyClass want to maintain an association to it, then use pointer:

class MyClass
{
public:
    MyClass();
private:
    Animals * animals;
};

The choice depends on the object ownership model.

There are many considerations involved.

In the containment approach, the memory for animals is allocated along with the MyClass object. They always go together and MyClass fully owns animals.

In the pointer approach, they are two separate pieces of memory and need to be allocated separately. It is an association without any ownership. Throughout the lifetime of MyClass, multiple things may happen:

  • myclass does not associate to any Animals, i.e. animals = nullptr
  • myclass may associate to different Animals at different time, i.e. animals = a1; /* ... */; animals = a2;

Moreover multiple objects, either MyClass objects or other type of objects, may hold the sameanimals` pointer.

If the animals object is destroyed, then these objects have a risk of using the stale pointer, hence some mechanism is necessary to avoid that.

With pointer approach, one can use run time polymorphism which is not possible in the containment approach. For example

void MyClass::setAnimal(Animal * a) {
  animal = a;
}

Animal * a1 = new Lion;
Animal * a2 = new Tiger;

MyClass x1;
x1.setAnimal(a1);

MyClass x2;
x2.setAnimal(a2);
Arun
  • 19,750
  • 10
  • 51
  • 60
0

From a design point of view, MyClass is a container of one Animal. In the first example you always have an Animal. In the second example you may or may not have an Animal.

For example if you have a cage with a bird, your first cage always has a bird and it can not be empty of a bird, but the second example you may or may not have a bird.

This is called Cardinality (0, 1) in databases. You can think of it like having an collection of Animals, with one or zero elements (even tough you don't have an array).

The second aspect is that, in the first example, you always have the same Animal, and you can't pass around it freely and the lifetime of the Animal depends exclusively on the container. The second example allows to move the Animal to a new container or to have the same Animal in two different containers and to decouple the life of the Animal from the container.

Then, with C++, you have to consider memory allocation and ownership, where we usually use smart pointers to deallocate the Animal.

vz0
  • 32,345
  • 7
  • 44
  • 77