views:

96

answers:

3

Consider the following code:

struct Calc
{
   Calc(const Arg1 & arg1, const Arg2 & arg2, /* */ const ArgN & argn) :
      arg1(arg1), arg2(arg2), /* */ argn(argn), 
      coef1(get_coef1()), coef2(get_coef2()) 
   {
   }

   int Calc1();
   int Calc2();
   int Calc3();

private:
  const Arg1 & arg1;
  const Arg2 & arg2;
  // ...
  const ArgN & argn;

  const int coef1; // I want to use const because 
  const int coef2; //      no modification is needed.

  int get_coef1() const {
     // calc coef1 using arg1, arg2, ..., argn;
     // undefined behavior?     
  }
  int get_coef2() const {
     // calc coef2 using arg1, arg2, ..., argn and coef1;
     // undefined behavior?
  }

};

struct Calc is not completely defined when I call get_coef1 and get_coef2 Is this code valid? Can I get UB?

+3  A: 

Since the variables your calculation depend on are already initialized at the time of the call, it should not be undefined behavior. See this question for related information.

Space_C0wb0y
And keep in mind that members are initialized in the order in which their declarations appear, not the order in which they appear in the initializer list. Here it's the same but be aware that simply putting `const int coef1;` above `const Arg1` (and keeping your initializer list the same) *would* create UB.
Tyler McHenry
My question is not about the order of initialization. The order in which their declarations appear is ok. I ask about functions `get_calc1`. Is `this`-pointer valid, for example? `arg2` is initialized, yes, true. But can I get access to `arg2` in the `get_calc1`?
Alexey Malistov
It's perfectly fine to call member functions that only refer to initialized member attributes.
Mark B
A: 

Not it's not undefined, but you have to be absolutely sure that those member functions are only using initialised values. Note also that values are initialised in the order that they appear in the class not the order they appear in the initialisation list. For example:

struct Foo
{
  int a, b;
  int c;
  Foo(): c(1), a(1), b(1) {}
};

In that constructor, the variables are initialised in the order a, b, then c, the order in the list means nothing. So if you want the value of a to be initialised using some calculation on b and c then you'll need to move the declaration of a to a point after that of b and c.

Peter Alexander
Thnks. But my question is not about the order of initialization. You may notice that the order was all right.
Alexey Malistov
I answered that in the first few words. It's not undefined, provided the order is right, which it is in your case, so you're fine.
Peter Alexander
+9  A: 

12.6.2.8: Member functions (including virtual member functions, 10.3) can be called for an object under construction. Similarly, an object under construction can be the operand of the typeid operator (5.2.8) or of a dynamic_cast (5.2.7). However, if these operations are performed in a ctor-initializer (or in a function called directly or indirectly from a ctor-initializer) before all the mem-initializers for base classes have completed, the result of the operation is undefined.

So you can initialize your class members this way, but not base classes. And, as others pointed, you should be aware of members initialization order, if your function uses some of their values.

Tadeusz Kopec
+1 because it is more to the point of what the OP actually wanted to know.
Space_C0wb0y