code
code

Reputation: 5642

When to use a member pointer variable in C++

I have a question about C++ design/implementation for best practice. I find myself having trouble deciding whether a member variable should be a pointer or not a pointer.

Lets say I have a class like this:

class Person{
     public:
        string name;
        int age;
        Child c;
};

Lets say that I want the "Child c" to be dynamic. Lets say that upon the creation of a "Person", I am not sure whether or not the Person has a child. It may be that the Person does have a child and does not have a child. And with this in mind, I want to be able to check in the code if the Person has a child.

Is it better to declare it as "Child* c" or "Child c"?

Given this, is it better to

class Person{
         public:
            string name;
            int age;
            Child* c;
    };

Upvotes: 3

Views: 231

Answers (3)

Filip Roséen
Filip Roséen

Reputation: 63797

Introduction

If you want Person to either have a child, or not, there's really no question; you cannot declare Person to have a data-member of type Child. By having a child as data-member, Person will inconditionally have one as a member.

You can of course solve this by having a pointer-to-Child, then the Person will either be able to refer to a Child if such is present, or have a nullptr in the pointer-to-Child to express that no such child exists.


Further thoughts

You need to decide whether Person should own a child, or just be able to refer to one.

  • If you decide that Person is the owner of its child, you are recommended to express this ownership through a std::unique_ptr, this will also ease handling the lifetime of said child.

  • If you want Person to share a child between other instances (or other some other piece of code), use a std::shared_ptr.

  • If you just want Person to be able to refer to a child (no ownership at all), and being able to change what child (if any child at all) a Person refers to; use a raw-pointer.

  • If you want Person to be able to refer to a child already in existance, from the start- until the end of its lifetime, use a reference initalized by the constructor of Person.


What if I really want a child as data-member of every Person?

You could have Child contain some sort of information that would tell you about its inner state, having either "alive" or "is not alive" but this is not as clear in terms of expressiveness, or express the "has a child" inside Person using a similar method.

Upvotes: 4

jsantander
jsantander

Reputation: 5102

If you add a non-pointer attribute you bind the lifecycle of that object to the lifecyle of the containing object.

If you don't desire that, then you need a pointer.

Alternatively you could have some sort of container (e.g. std::vector) where to store the attribute... but that would imply semantics of (0..*) instead of (0..1)

Other reasons for preferring/requiring a pointer:

  1. Hiding details of implementation (use a pointer to a parent abstract class) or having the ability to store objects from different parts of a hierarchy.
  2. Avoiding a circular reference.

What sort of pointer is up to you. If you want to avoid trouble, use either shared_ptr or unique_ptr. If you use raw pointers, then you should be concerned about the ownership of the allocated object, i.e. who is in charge of allocating it and most important who is responsible for deallocating it.

Upvotes: 0

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385104

Pointers are not appropriate here at all, and you do not need dynamic allocation to obtain an "optional" member.

It is better to use a boost::optional<Child>.

If you were to use a pointer, you'd use a smart pointer that manages the lifetime of the pointee for you.

Upvotes: 3

Related Questions