Julik
Julik

Reputation: 7856

Should I store a completely incapsulated member by reference, by value or by ptr?

So I have the standard C++ setup with an object that stores another object. The stored object is owned completely, it's never leaked to the outside. The member is non-const.

class Container
{
private:
    Contained item;
}

As I understand, when my Container is instantiated the default constructor will be called on the item member and I don't have to manage it in the initializer list. Also do I understand it correctly that when my object is destroyed the dtor on the item will be called automatically?

Another option would be to store it by reference of course

class Container
{

private:
    Contained& item;

public:

    Container() : Contained()
    {

    }
}

in which case I don't know whether I should delete it in the dtor.

Yet another option is to store it by ptr

class Container
{
private:
    Contained* item;
public:
    Container()
    {
        item = new Contained();
    }

    ~Container()
    {
        delete item;
    }
}

Knowing that my item never gets returned to the caller and never bleeds into the outside API and never gets reassigned, what is the best way to proceed? As I mentioned, the item member is not const (it will be a self-resizing data structure).

Upvotes: 2

Views: 115

Answers (5)

CashCow
CashCow

Reputation: 31445

Most of the time, you want to reduce the dependencies on your class. If this class forms an integral part of the interface (even if the member is private) then you can assume that anyone using your class will be using this one.

In such a case, having it as a member variable makes sense.

Where it is an implementation detail of your class, you should hide this detail from the users by using a forward declaration, so use a type that allows a forward declaration.

It is highly unlikely that it will be a reference. A reference must be initialsed on construction of your class, and so the constructor would probably have to pass in the object it refers to. Declaring it with new and dereferencing is going to lead to confusion.

If it is a pointer, your class can manage its lifetime with the destructor. In this case I often will use a raw pointer as it is well under control and my destructor can happily delete it, assuming my class is non-copyable.

If you use shared_ptr, you can use a forward declaration. But beware that your semantics are now that if you copy your object, all the copies will have a pointer to the same underlying object. If this is not what you want, shared_ptr is probably wrong. In addition, if you use shared_ptr when your class is non-copyable, it isn't really shared.

So unless you can use unique_ptr which allows a forward declaration, I would go for the raw pointer and a non-copyable class.

If your member does remain an implementation detail but is something that is pretty standard, like a map or a vector, it is not worth "encapsulating it" to the extent of using a forward declaration, only the types that are contained within the map or the vector, but not the map or vector itself.

Upvotes: 0

qdii
qdii

Reputation: 12973

Contrary to Luchian Grigore, I’d go for pointer/reference method: storing the encapsulated object as a reference or pointers lets you forward-declare it, hence saving compilation time.

In addition to that, it lets you have init() and destroy() member functions that would in turn call the constructor and destructors of the encapsulated object, as well as perform initialization of the other parts of the object. This way, a bad initialization can be handled by the return value of init().

Upvotes: 0

Johan Kotlinski
Johan Kotlinski

Reputation: 25759

The easiest is to store the object itself. Using reference for this purpose is, I would say, confusing. One advantage with using the pointer is that you then may be able to avoid defining the Contained type in the header file - you can instead forward declare Contained, and keep all the details inside the .cpp file.

Upvotes: 2

Luchian Grigore
Luchian Grigore

Reputation: 258638

In this case, it's best to store the object itself, yes. Storing it by reference will only create an alias to the object, so your class is not the actual owner. Storing via a pointer is useless, unless your object is a base class and you might want to store a derived object.

Upvotes: 1

Nim
Nim

Reputation: 33645

The first way is the best way in my opinion (it appears you don't need the object to be lazily constructed). The second way requires that you pass in the object from the outside and that it's lifetime is guaranteed, and the third way is really only good if you want lazy instantiation (i.e. only create the object on first use).

Upvotes: 1

Related Questions