kfmfe04
kfmfe04

Reputation: 15327

C++ Refactoring: Initialization Ordering In Constructors

Suppose I need to call a free GlobalInitializer() before my constructor initializes any member variables. For example:

class Foo {
  public:
    Foo() : bar_()
    {
      // calling GlobalInitializer() here is too late
    }
  Bar bar_;
};

Calling GlobalInitializer() in Foo is too late because I need to call it before bar_ is initialized. My hacky work around for this has been to create a super-class:

class MyInitializer {
  protected:
    MyInitializer() {
      GlobalInitializer();
    }
};
class UglyFoo : public MyInitializer
{
  public:
    UglyFoo() : bar_()
    { }
  Bar bar_;
};

UglyFoo gets the job done, but it requires this ugly MyInitializer class. Is there a cleaner design pattern or refactoring which will achieve the same result?

Additional Note: GlobalInitializer() is an expensive call that I want to avoid unless the user instantiates a Foo(). There are guards inside GlobalInitializer() against multiple calls. Also, there may be other classes, say FooBar, that also need to call GlobalInitializer(), but in one process, GlobalInitializer() will actually do work once (if Foo or FooBar is instantiated) or not even once (if there are no instantiations of Foo or FooBar).

Upvotes: 1

Views: 226

Answers (5)

kfmfe04
kfmfe04

Reputation: 15327

Came across to me in a dream: change bar_ into a pointer:

class Foo {
  public:
    Foo()
    {
      GlobalInitializer();
      // now we can call GlobalInitializer() in time
      bar_ = new Bar; 
    }
    ~Foo()
    {
      delete bar_;
    }

  private:
    Bar* bar_;
};

Upvotes: 0

Luchian Grigore
Luchian Grigore

Reputation: 258568

You should probably re-think your design.

A good design implies loose-coupling. If your object creation depends on a different method call to work, there's something seriously wrong there.

If you do need this, you should probably call GlobalInitializer inside the constructor of bar_, but the best way to go about this is re-thinking your design.

Upvotes: 1

Kristopher Johnson
Kristopher Johnson

Reputation: 82535

class Foo {
private:
    struct Initializer {
        Initializer() { GlobalInitializer(); }
    };
    Initializer initializer__;  // declare before bar__ to ensure it is constructed first

public:
    Foo() : bar_()
    {
    }

    Bar bar_;
};

Upvotes: 4

David
David

Reputation: 28178

Presumably you could refactor whatever GlobalInitializer initializes to not be global anymore. Then your options open up on how to give your class that data. You know, because globals are bad and all.

Upvotes: 0

mah
mah

Reputation: 39807

What you're doing seems to violate object oriented values as your classes are unreasonably dependent on something outside them; I would recommend redesigning your classes to avoid that instead.

That being said, an option that fits your design model without making each class inherit another is to create the MyInitializer class as a singleton object, and add a MyInitializer to each class that depends on this initialization. The singleton will only perform its initialization the first time it gets instantiated.

Upvotes: 0

Related Questions