SunlessVoid
SunlessVoid

Reputation: 7

Depended initializatoin list

I'm kind of new to C++ and encountered this desgin problem.

Let's say I have these classes:

class Dependee
{
public:
    // Constructors
    initialize();
};

class Depender
{
public:
    Depender(Dependee dependee);
    // Other constructors and stuff
};

class World
{
public:
    World();
private:
    Dependee dependee_;
    Depender depender_;
};

Now, depender depends on dependee for construction. But dependee not only has to be constructed prior to depender's construction, but also initialized using initialize().

There are several ways to solve this, the two I am considering is a static method inside the World class

static Dependee initDependee()
{
    Dependee dependee();
    if(!dependee.initialize())
    {
        throw SomeException();
    }

    return dependee;
}

and then doing:

World::World():
dependee_(initDependee()),
depender_(dependee_)
{}    

or just initializing both using the default constructors, and doing the rest of the work in World's constructor

World::World() :
dependee_(),
depender_()
{
    Dependee dependee();
    dependee.initialize();

    dependee_ = dependee;

    Depender depender(dependee);

    depender_ = depender;
}

Obvoiusly I am open to any other solution, but consider that Dependee comes from an outside library.

PS: Is there are any good books on proper C++ design and coding conventions that you would recommend?

Thanks!

Upvotes: 0

Views: 72

Answers (2)

SergeyA
SergeyA

Reputation: 62583

Two-phase initialization generally is ill-advised. C++ has constructors! However, taken that it comes from third-party library and there is nothing you can do about it, I would certainly not recommend using default constructor for your Depender. Constructors were invented (among other things, of course) to preserve class invariants.

The problem with your static initializer is, of course, a copy-construction of your Dependee. Now, do you need a COPY of your dependee in your depender class? Or would a pointer do? Obviously, if it is pointer, you can simply use unique_ptr. Issues with that? Of course, dynamic allocation, which is not always preferred.

So how would you solve this dilemma? I would suggest a wrapper. Something like this:

template <class WRAPPEE> struct Wrapper {
    Wrapper() { wrappee.initialize(); }
    WRAPPEE& operator() { return wrappee; } // Add const version as well
private:
    WRAPPEE wrappee;
};

typedef Wrapper<Dependee> dependee_t;
dependee_t dependee;
....
depender(dependee);

This should work reasonable well.

Upvotes: 1

SingerOfTheFall
SingerOfTheFall

Reputation: 29966

You are spawning a lot of copies either way. I would do it with shared pointers unless you really need to store separate copies of Dependee in World and Depender.

class Dependee
{
public:
    // Constructors
    initialize();
};

class Depender
{
public:
    Depender(shared_ptr<Dependee> dependee);
    // Other constructors and stuff
};

class World
{
public:
    World() : dependee_(new Dependee())
    {
        dependee_.initialize();
        depender_.reset(new Depender(dependee_));
    }
private:
    shared_ptr<Dependee> dependee_;
    shared_ptr<Depender> depender_;
};

This way you only construct and store 1 copy of every object.

Upvotes: 1

Related Questions