Iurii Sorokin Iurii Sorokin - 2 months ago 11
C++ Question

Initialize Derived class member variable before calling Base class constructor. Is this UB?

I would like to initialize a member variable of a Derived class, and after that pass it to the Base class constructor. I came up with the solution below (also here: http://cpp.sh/4uu4q)

1) Does the following code have a defined or an undefined behavior (UB) ?

2) Is what I am attempting to do an indication of a bad design?

struct Data {
int fValue;

Data( int value = -1 ) : fValue( value )
{}
};


struct Base {
Base( const std::unique_ptr<Data> & derivedData ) {
std::cout << "Constructing Base derivedData=" << derivedData->fValue << std::endl;
}
};


struct Derived : public Base {
std::unique_ptr<Data> fData = std::move( fData );

Derived() : Base( ConstructData() )
{}

const std::unique_ptr<Data> & ConstructData() {
fData.release();
fData.reset( new Data(777) );
std::cout << "in ConstructData: fData->fValue =" << fData->fValue << std::endl;
return fData;
}
};


int main() {
Derived d;
std::cout << "In main: d.fData->fValue =" << d.fData->fValue << std::endl;
return 0;
}

Answer

I would like to initialize a member variable of a Derived class, and after that pass it to the Base class constructor.

In C++, the order of construction is of the base part(s) before the derived parts. This is because it is far more common for the derived parts to (potentially) be constructed in terms of the base parts. In order to make this well-defined, the base-then-derived order is specified. Using derived in the base is undefined, therefore.

If you want your base to use derived members, there's a way to ensure the order is OK. Make the "members" base classes too. Note that boost::base_from_member is built exactly for making this more convenient.

Say you have some

class member_type{};

And you'd like to have derived have a member_type member, and derive from base. Then you could use:

class derived : 
    private boost::base_from_member<member_type>,
    public base {
    using my_member_type = private boost::base_from_member<member_type>;

public:
    derived();
};

Note that now derived subclasses both my_member_type and base (in that order). Hence, the latter can use the former in its construction.

derived::derived() : 
    my_member_type{3},
    base{my_member_type::member} {
}
Comments