own initialization before calling parent's constructor

A

avasilev

Hello,
The subject says it - is it legal to initialize fields of the derived
before calling the parent's consctructor, in the initialization list.
For example:

class Base
{
public:
int b;
B(int arg):b(arg){};
};

class Derived: public Base
{
int d;
int calculateValue() {return d+5};
Derived(int arg):
d(arg), B(calculateValue()){};
};

Greetings
Alex
 
V

Victor Bazarov

The subject says it - is it legal to initialize fields of the derived
before calling the parent's consctructor, in the initialization list.

What's the "parent"? A base class subobject?
For example:

class Base
{
public:
int b;
B(int arg):b(arg){};
};

class Derived: public Base
{
int d;
int calculateValue() {return d+5};
Derived(int arg):
d(arg), B(calculateValue()){};

It's totally legal to write the code like that. It's not going to work
as you expect, though. First, the base class subobjects are initialized
in the order of their declaration, then the data members, *in the order
they are declared*. Of course, calling a member function with 'd'
uninitialized will have undefined behavior... But it's totally legal.
};

Greetings
Alex

V
 
B

Bart v Ingen Schenau

avasilev said:
Hello,
The subject says it - is it legal to initialize fields of the derived
before calling the parent's consctructor, in the initialization list.

It is immaterial if it is legal or nor, because it is impossible.
The order of initialisation of a class's base-classes and members is not
dependent on the order they are specified in in the initializer-list, but
rather the order they are declared in in the class's definition.

If you compile your example with g++, with the warning flags -Wreorder or
-Wall, then g++ will complain that the initialization order is different
from the order in your initializer list.
Greetings
Alex

Bart v Ingen Schenau
 
A

avasilev

It is immaterial if it is legal or nor, because it is impossible.
The order of initialisation of a class's base-classes and members is not
dependent on the order they are specified in in the initializer-list, but
rather the order they are declared in in the class's definition.

If you compile your example with g++, with the warning flags -Wreorder or
-Wall, then g++ will complain that the initialization order is different
from the order in your initializer list.
Yes, you are right about the warning. AFAIK, it is there to prevent
initializing mutually-dependent members which are not initialized in
the sequence specified in the class declaration.
In my case, however, I don't have such a dependency. In fact, I have a
reverse dependency - the call to the base constructor depends on some
derived-class members being initialized already. Of course the abse
constructor itself will never depend on derived class members, but
here I'm talking about constructor arguments (see example).

Alex
 
A

avasilev

What's the "parent"?  A base class subobject?




It's totally legal to write the code like that.  It's not going to work
as you expect, though.  First, the base class subobjects are initialized
in the order of their declaration, then the data members, *in the order
they are declared*.  Of course, calling a member function with 'd'
uninitialized will have undefined behavior...

But I'm not doing this. My problem is that i need some derived-class
members initialized, in order to calculate the argument of the base's
constructor.

Alex
 
V

Victor Bazarov

But I'm not doing this. My problem is that i need some derived-class
members initialized, in order to calculate the argument of the base's
constructor.

Wrong. You don't need the data member initialized. If you think you
do, you're either don't understand the meaning of your base class and
its function, or your design is wrong. Generally speaking, what you
need is one place from which both the initialization of the base class
subobject will get its argument *and* the data member is going to be
initialized. For instance:

class Derived : public Base
{
static int calculateValue(int arg) { return arg+5; }
Derived(int arg) : Base(calculateValue(arg)), d(arg) {}
...

V
 
V

Victor Bazarov

Yes, you are right about the warning. AFAIK, it is there to prevent
initializing mutually-dependent members which are not initialized in
the sequence specified in the class declaration.
In my case, however, I don't have such a dependency. In fact, I have a
reverse dependency - the call to the base constructor depends on some
derived-class members being initialized already. Of course the abse
constructor itself will never depend on derived class members, but
here I'm talking about constructor arguments (see example).

Either there *is* no such dependency (IOW, you are just *imagining* it)
or you introduced that dependency because your model is incorrect. Fix
your model or implement the dependency differently.

V
 
K

Kevin McCarty

Yes, you are right about the warning. AFAIK, it is there to prevent
initializing mutually-dependent members which are not initialized in
the sequence specified in the class declaration.

Realize that the base class (or classes) is also in some respects a
member of the derived class, and is always initialized (including, per
12.6.2 of C++ 2003 standard, the evaluation of any of its constructor
arguments) before any other members of the derived class.

In my case, however, I don't have such a dependency. In fact, I have a
reverse dependency - the call to the base constructor depends on some
derived-class members being initialized already. Of course the abse
constructor itself will never depend on derived class members, but
here I'm talking about constructor arguments (see example).

Then your code is simply not going to work. That's just how the
language is. The derived class instance (and any non-static members
of it) does not yet exist at the time the base class constructor is
invoked and an attempt is made to evaluate Derived::calculateValue().
It will quite possibly return garbage. If you are very unlucky, it
will work by accident until you upgrade to a new compiler version or
change platforms or something.

You have a few alternatives for a work around, all of which have their
ups and downs:

1) Use a static member function of the derived class for the
calculation

class Base
{
public:
int b;

// your constructor was misnamed "B"
Base(int arg):b(arg){}
};

class Derived: public Base
{
int d;

// added static function
static int calculateValueFrom(int arg) { return arg+5; }

// you probably want ctor and calc fn to be public
public:

// rewrite non-static in terms of static to avoid redundancy
int calculateValue() { return calculateValueFrom(d); }

Derived(int arg):
Base(calculateValueFrom(arg)), d(arg) { }
};



2) Use two-phase initialization for the base object

class Base
{
public:
int b;

// added default ctor
Base() : b(0) { }

Base(int arg):b(arg){}

protected:
// added setter for b
void setB(int arg) { b = arg; }
};

class Derived: public Base
{
int d;

// again, added public keyword here
public:

int calculateValue() {return d+5;}

Derived(int arg):
Base(), // not actually needed, used by default
d(arg)
{ setB(calculateValue()); } // 2-phase init
};


3) Multiple inheritance: move the calculation logic into another base
class, and rely on the fact that base class constructors are called in
the order in which they are inherited from.

// Calculation logic moved here
class Calculator
{
protected: // presuming Derived needs access
int d;

public:
int calculateValue() {return d+5;}

Calculator(int arg) : d(arg) { }
};

class Base
{
public:
int b;
Base(int arg):b(arg){}
};

class Derived:
public Calculator, public Base // must have this order
{
public:
Derived(int arg):
Calculator(arg),
// C++03 std 12.6.2 ensures that Calculator is
// constructed when calculateValue() is called:
Base(calculateValue()) { }
};

- Kevin B. McCarty
 
A

avasilev

Either there *is* no such dependency (IOW, you are just *imagining* it)
or you introduced that dependency because your model is incorrect.  Fix
your model or implement the dependency differently.

The reason I am resorting to this, is actually because I would like to
do some caching of calculated result, which I then use to pass to the
base's constructor, and will use further in the object's lifetime for
other purposes. Normally I would store the result in a variable, and
not initialize any members, but given the limited syntax of
initializer lists, I cannot implement logic that I would do normal
code. Let me clarify with another example:

struct Base
{
Base(int v) {...};
}

struct Derived: public Base
{
int d;
void veryCostlyCalculation()
{
....
d = <calculation result>
}

Derived()
:veryCostlyCalculation(), Base(d) {}
};


In an initialization list, how can I store the result of
veryCostlyCalculation() in a local variable, so that I don't use
members?
 
A

avasilev

Hi Kevin,
Thanks for the detailed response.
Then your code is simply not going to work.  That's just how the
language is.  The derived class instance (and any non-static members
of it) does not yet exist at the time the base class constructor is
invoked

I think that says it all! That was also my doubt, and the reason to
ask.
You have a few alternatives for a work around, all of which have their
ups and downs:

1) Use a static member function of the derived class for the
calculation

This will not do - actually my purpose is to cache the result from the
calculation for later reuse, but in an initializer list I can't have
local variables, this is why I wanted to use a member variable for
this purpose.

2) Use two-phase initialization for the base object
3) Multiple inheritance: move the calculation logic into another base
class, and rely on the fact that base class constructors are called in
the order in which they are inherited from.

These will technically do the job, but my optimization is too small to
resort to complicating the design in such ways. I guess I will just
leave the optimization for later.
Thanks
Alex
 
V

Victor Bazarov

The reason I am resorting to this, is actually because I would like to
do some caching of calculated result, which I then use to pass to the
base's constructor, and will use further in the object's lifetime for
other purposes. Normally I would store the result in a variable, and
not initialize any members, but given the limited syntax of
initializer lists, I cannot implement logic that I would do normal
code. Let me clarify with another example:

struct Base
{
Base(int v) {...};
}

struct Derived: public Base
{
int d;
void veryCostlyCalculation()
{
....
d =<calculation result>
}

Derived()
:veryCostlyCalculation(), Base(d) {}
};


In an initialization list, how can I store the result of
veryCostlyCalculation() in a local variable, so that I don't use
members?

Are you joking? Pulling my leg, by any chance? Why can't you just do

static int veryCostlyCalculation() {
...
return <calculation result>;
}

Derived : Base(veryCostlyCalculation()) {}

?

V
 
G

Gert-Jan de Vos

The reason I am resorting to this, is actually because I would like to
do some caching of calculated result, which I then use to pass to the
base's constructor, and will use further in the object's lifetime for
other purposes. Normally I would store the result in a variable, and
not initialize any members, but given the limited syntax of
initializer lists, I cannot implement logic that I would do normal
code. Let me clarify with another example:

struct Base
{
  Base(int v) {...};

}

struct Derived: public Base
{
  int d;
  void veryCostlyCalculation()
  {
    ....
    d = <calculation result>
  }

  Derived()
  :veryCostlyCalculation(), Base(d) {}

};

In an initialization list, how can I store the result of
veryCostlyCalculation() in a local variable, so that I don't use
members?

This works but isn't pretty:

#include <iostream>

struct Base
{
Base(int v) : dBase(v) { }

int dBase;
};

struct Derived : public Base
{
Derived(int cachedValue = 0) :
Base(cachedValue = veryCostlyCalculation()),
dDerived(cachedValue)
{
}

static int veryCostlyCalculation()
{
std::cout << "veryCostlyCalculation\n";
return 12;
}

int dDerived;
};

int main()
{
Derived d;

std::cout << d.dBase << "\n";
std::cout << d.dDerived << "\n";
}

C++11 supports constructor forwarding. You could have the default
constructor
forward to a private constructor with the argument to be calculated
once like
this:

class Derived : public Base
{
public:
Derived() : Derived(veryCostlyCalculation()) { }

private:
Derived(int calculatedValue) :
Base(calculatedValue),
dDerived(calculatedValue)
{
}

static int veryCostlyCalculation()
{
std::cout << "veryCostlyCalculation\n";
return 12;
}

int dDerived;
};

And you can simulate constructor forwarding in C++03 by adding an
extra derived class:

class DerivedBase : public Base
{
public:
// ...

protected:
Derived(int calculatedValue) :
Base(calculatedValue),
dDerived(calculatedValue)
{
}

int dDerived;
};

class Derived : public DerivedBase
{
public:
Derived() : DerivedBase(veryCostlyCalculation()) { }

private:
static int veryCostlyCalculation()
{
std::cout << "veryCostlyCalculation\n";
return 12;
}
};

Hope this helps!

Gert-Jan
 
V

Victor Bazarov

Hi Kevin,
Thanks for the detailed response.

I think that says it all! That was also my doubt, and the reason to
ask.


This will not do - actually my purpose is to cache the result from the
calculation for later reuse, but in an initializer list I can't have
local variables, this is why I wanted to use a member variable for
this purpose.



These will technically do the job, but my optimization is too small to
resort to complicating the design in such ways. I guess I will just
leave the optimization for later.

You could also try using the default argument mechanism:

class Derived : public Base
{
...
explicit Derived(int a = costlyCalculation()) : Base(a) {}
};

V
 
V

Victor Bazarov

This works but isn't pretty:

#include<iostream>

struct Base
{
Base(int v) : dBase(v) { }

int dBase;
};

struct Derived : public Base
{
Derived(int cachedValue = 0) :
Base(cachedValue = veryCostlyCalculation()),
dDerived(cachedValue)
{
}

static int veryCostlyCalculation()
{
std::cout<< "veryCostlyCalculation\n";
return 12;
}

int dDerived;

I think the OP has indicated that there is no need in a data member
here. He was just trying to use it as the temporary storage.
};

int main()
{
Derived d;

std::cout<< d.dBase<< "\n";
std::cout<< d.dDerived<< "\n";
}

C++11 supports constructor forwarding. You could have the default
constructor
forward to a private constructor with the argument to be calculated
once like
this:

class Derived : public Base
{
public:
Derived() : Derived(veryCostlyCalculation()) { }

private:
Derived(int calculatedValue) :
Base(calculatedValue),
dDerived(calculatedValue)
{
}

static int veryCostlyCalculation()
{
std::cout<< "veryCostlyCalculation\n";
return 12;
}

int dDerived;
};

And you can simulate constructor forwarding in C++03 by adding an
extra derived class:

class DerivedBase : public Base
{
public:
// ...

protected:
Derived(int calculatedValue) :

explicit DerivedBase(int calculatedValue) :
Base(calculatedValue),
dDerived(calculatedValue)
{
}

int dDerived;
};

class Derived : public DerivedBase
{
public:
Derived() : DerivedBase(veryCostlyCalculation()) { }

private:
static int veryCostlyCalculation()
{
std::cout<< "veryCostlyCalculation\n";
return 12;
}
};

In order to prevent any problems with clients trying to use
'DerivedBase' class by itself, I'd probably use a private class like this:

class Base {
public:
Base(int);
};

class Derived : public Base
{
struct Helper {
Helper(int v) : value(v) {}
int value;
};
public:
Derived(Helper h = Helper(veryCostlyCalculation())) :
Base(h.value)
{ }

static int veryCostlyCalculation();
};

int main()
{
Derived d;
}

V
 
A

avasilev

Hi Gert-Jan,
class DerivedBase : public Base
{
public:
    // ...

protected:
    Derived(int calculatedValue) :
        Base(calculatedValue),
        dDerived(calculatedValue)
    {
    }

    int dDerived;

};

class Derived : public DerivedBase
{
public:
    Derived() : DerivedBase(veryCostlyCalculation()) { }

private:
    static int veryCostlyCalculation()
    {
        std::cout << "veryCostlyCalculation\n";
        return 12;
    }

};
I think this is the most elegant way to do it, at least in my case I
will use this approach.
Thanks a lot
Alex
 
G

Goran

The reason I am resorting to this, is actually because I would like to
do some caching of calculated result, which I then use to pass to the
base's constructor, and will use further in the object's lifetime for
other purposes. Normally I would store the result in a variable, and
not initialize any members, but given the limited syntax of
initializer lists, I cannot implement logic that I would do normal
code. Let me clarify with another example:

struct Base
{
  Base(int v) {...};

}

struct Derived: public Base
{
  int d;
  void veryCostlyCalculation()
  {
    ....
    d = <calculation result>
  }

  Derived()
  :veryCostlyCalculation(), Base(d) {}

};

In an initialization list, how can I store the result of
veryCostlyCalculation() in a local variable, so that I don't use
members?

Really, is this a joke? Just calculate your value before going to a
constructor. It then becomes

Derived(int calculatedValue)
: d(calculatedValue)
, Base(calculatedValue)
{
}

If you don't want to expose veryCostlyCalculation to outside world,
you can do:

class Derived
{
public:
static Derived Create()
{
return Derived(veryCostlyCalculation());
}
private:
Derived(int calculatedValue)
{
: d(calculatedValue)
, Base(calculatedValue)
}
}

Your veryCostlyCalculation makes no sense, because you want to call it
before you have a constructed members, so you can't access them. If
so, it can only be static, and even that is dubious. Further, if Base
holds calculatedValue already, why can't Derived use that!?

Goran.
 
A

avasilev

Really, is this a joke? Just calculate your value before going to a
constructor. It then becomes

Derived(int calculatedValue)
calculatedValue is an internal stuff that does not concern the outer
world, so passing as constructor argument is out of the question.
: d(calculatedValue)
, Base(calculatedValue)
{

}

And then we are where we started - initializing derived member d,
before calling base constructor :)
 
V

Victor Bazarov

calculatedValue is an internal stuff that does not concern the outer
world, so passing as constructor argument is out of the question.

And then we are where we started - initializing derived member d,
before calling base constructor :)

No. 'Base' is initialized first. Then 'd'. The initialization of
'Base' does not depend on 'd' having the "correct" value.

V
 
K

Kevin McCarty

Hi Kevin,
Thanks for the detailed response.


I think that says it all! That was also my doubt, and the reason to
ask.



This will not do - actually my purpose is to cache the result from the
calculation for later reuse, but in an initializer list I can't have
local variables, this is why I wanted to use a member variable for
this purpose.

It *is* cached and can be re-used later. In the #1 replacement design
I suggested, it is cached into Base::b, which you had as public so it
can be accessed by any member function of Derived (or anything else
for that matter), including within the initialization list of the
Derived constructor:

class Derived: public Base
{
int d, cachedResult;

static int calculateValueFrom(int arg) { return arg+5; }

public:

int calculateValue() { return calculateValueFrom(d); }

Derived(int arg):
Base(calculateValueFrom(arg)),
d(arg),
cachedResult(Base::b) { }

};

If Base::b is actually private and for some reason you can't modify
the definition of Base to add an accessor for b, then you can
interpose another class Intermediate between Base and Derived in the
inheritance hierarchy, pass the result of (static)
Derived::calculateValueFrom(int) into the Intermediate constructor,
which stores it there, and have that constructor pass its argument
along into the Base constructor. Then Derived can access the cached
value from Intermediate (this is less than ideal as now you have two
copies of the cached value, of course, one in each parent class --
hope they don't get out of sync).

[On refresh, I think this is also what Gert-Jan suggested.]


From your other post:

And then we are where we started - initializing derived member d,
before calling base constructor :)


No. The order in which objects are initialized before the ctor body
is reached is dependent upon the class declaration, and NOT upon the
order in which they are written in the ctor initializer list: that
order is simply ignored. In the code above, Base's ctor will still be
called before Derived::d is initialized.

It is true that g++ -Wall will warn about the order of the initializer
list above not being consistent with the actual order of
initialization. But in this case it does not matter anyway since
there is no longer a dependency of Base on d nor vice versa. It would
be nice if g++ were smart enough not to display that warning unless it
would actually make a difference, but I suppose that's a hard problem
in general due to possible side effects of ctor arguments.

- Kevin B. McCarty
 
J

Joe keane

In fact, I have a
reverse dependency - the call to the base constructor depends on some
derived-class members being initialized already.

There is some case where the default language init just does -not-
work for you.

Better to make an 'uninit' constructor
and do it step-by-step.

If you try to use the C++ stuff
when it doesn't fit, you're just stabbing yourself.

[i don't know it reflects a design flaw,
IMHE this problem comes up with classes that otherwise seem to be fine]
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top