Reputation: 7
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
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
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