Подтвердить что ты не робот

Могут ли функции-члены использоваться для инициализации переменных-членов в списке инициализации?

ОК, переменные-члены могут использоваться, чтобы инициализировать другие переменные-члены в списке инициализации (с осторожностью относительно порядка инициализации и т.д.). Как насчет функций-членов? Чтобы быть конкретным, является ли этот фрагмент законным в соответствии со стандартом С++?

struct foo{
  foo(const size_t N) : N_(N),  arr_(fill_arr(N)) { 
    //arr_ = fill_arr(N); // or should I fall back to this one?
  }

  std::vector<double> fill_arr(const size_t N){
    std::vector<double> arr(N);
    // fill in the vector somehow
    return arr;
  }

  size_t N_;
  std::vector<double> arr_;
  // other stuff
};
4b9b3361

Ответ 1

Да, использование функции-члена в списке инициализации действительно и соответствует стандарту.

Элементы данных инициализируются в порядке их объявления (и что причина, по которой они должны появляться в списке инициализации в порядке их объявления - правило, которое вы соблюдали в своем примере). N_ сначала инициализируется, и вы могли бы передать этот элемент данных в fill_arr. fill_arr вызывается перед конструктором, но поскольку эта функция не имеет доступа к неинициализированным элементам данных (она вообще не обращается к элементам данных), ее вызов считается безопасным.

Вот некоторые релевантные исключения из последнего проекта (N3242 = 11-0012) стандарта С++:

§ 12.6.2.13: Функции членов (включая функции виртуальных членов, 10.3) можно вызвать для строящегося объекта. (...) Однако, если эти операции выполняются в ctor-инициализаторе (или в функции вызываемый прямо или косвенно из ctor-инициализатора) до того, как все mem-инициализаторы для базовых классов завершены, результат операция undefined. Пример:

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

class B : public A {
   int j;
public:
   int f();
   B() : A(f()), // undefined: calls member function
                 // but base A not yet initialized
   j(f()) { }    // well-defined: bases are all initialized
};

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

class D : public B, C {
   int i;
public:
   D() : C(f()), // undefined: calls member function
                 // but base C not yet initialized
   i(f()) { } // well-defined: bases are all initialized
};

§12.7.1: для объекта с нетривиальным конструктором, ссылаясь на любой нестатический член или базовый класс объекта до конструктор начинает выполнение результатов в undefined. Пример

struct W { int j; };
struct X : public virtual W { };
struct Y {
   int *p;
   X x;
   Y() : p(&x.j) { // undefined, x is not yet constructed
   }
};

Ответ 2

При инициализации объектов в списке инициализации объект еще не полностью сконструирован.
 Если эта функция пытается получить доступ к той части объекта, которая еще не построена, то это поведение undefined else. см. этот ответ.