how to prevent usage of class members not yet constructed?

放肆的年华 提交于 2021-02-07 18:27:26

问题


I have the following classes:

class A
{
public:
    A() { x = 0; std::cout<<"A default ctor()\n"; }
    A(int x_) { x = x_; std::cout<<"A normal ctor()\n"; }
    int x;
};

class B
{
public:
    B() { std::cout<<"B ctor()\n"; }
private:
std::string str;
};

and a function which creates an object B, taking an object A as parameter:

B
createB(const A& a) {
    std::cout<<"a int: "<<a.x<<"\n";
    return B();
}

if I design a class C, which has members of type A and B and constructs the B-object before A-object is constructed but using the A object to do so, this will compile without warnings but it will silently enter a bug:

class C
{
public:
    C(): b(createB(a)), a(10) {}
private:
    B b;
    A a;
};


int main()
{
    C c;
    return 0;
}

Of course, the above example is a trivial one, but I've seen it in real world, in much more complex code (it's Friday, 8:30 PM and I just fixed this bug which led to segfaults).

How can I prevent this from happening?


回答1:


I would agree with what others have suggested, namely that the onus is on the designer to ensure that objects are initialized before use. I see two ways of doing that in your case:

First (and easiest), reverse the order of a and b in the class definition:

class C
{
public:
    C(): b(createB(a)), a(10) {}
private:
    A a;
    B b;
};

Second, you could move a to a base class if you want to really emphasize that it's initialization occurs before that of other members:

class CBase
{
protected:
    CBase(): a(10) {}
protected:
    A a;
};

class C : private CBase
{
public:
    C(): b(createB(a)) {}
private:
    B b;
};



回答2:


I see three possible alternatives:

Require A to be constructed prior to constructing C:

class C
{
public:
   C(const A& a) : a_(a), b_(a) {}
private:
   A a_;
   B b_;
};

Construct A prior to constructing 'B':

Delaying the construction of B until A is complete. This stops the undefined behavior from happening, but doesn't enforce proper behavior via the interface (as options 1 and 3 do)

class C
{
public:
   C() : a_(/* construct as appropriate */)
   {
      b_.reset(new B(a_));
   }

private:
   A a_;
   std::unique_ptr<B> b_;
};

If the design allows for it, have B contain (and expose) A.

This appears possible from the trivial example, but in real life may not be:

class B
{
public:
   const A& my_a() {return a_;}
private:
   // construct as appropriate (?)
   A a_;
};

class C
{
private:
   B b_;
};


来源:https://stackoverflow.com/questions/13091561/how-to-prevent-usage-of-class-members-not-yet-constructed

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!