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

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

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
};

person ev-br    schedule 24.06.2012    source источник
comment
Вопрос хороший, но пример кода несколько искусственный. Что мешает вам объявить fill_arr как static и не сомневаться в том, что это законно?   -  person K-ballo    schedule 24.06.2012
comment
Будет ли это потокобезопасным? Я имею в виду, что есть вектор, локальный для fill_arr, если это static, должен ли я защищать его своего рода мьютексом?   -  person ev-br    schedule 24.06.2012
comment
std::vector<double> arr имеет автоматическое хранилище, поэтому для каждого вызова функции fill_arr будет его экземпляр. Это базовый C++...   -  person K-ballo    schedule 24.06.2012
comment
В этом примере лучше пометить fill_arr как const. Для удобства чтения.   -  person E_g    schedule 05.06.2020


Ответы (2)


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

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

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

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

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: Для объекта с нетривиальным конструктором обращение к любому нестатическому члену или базовому классу объекта до начала выполнения конструктора приводит к неопределенному поведению. Пример

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
   }
};
person Bojan Komazec    schedule 24.06.2012

Во время инициализации объектов в списке инициализации объект еще не полностью построен.
Если эта функция пытается получить доступ к части объекта, которая еще не создана, то это неопределенное поведение, иначе его хорошо.
см. этот ответ.

person Eight    schedule 24.06.2012
comment
В этом и суть вопроса: каковы правила порядка построения функций-членов? - person ev-br; 24.06.2012
comment
Поправьте меня, если я ошибаюсь: вопрос, на который вы ссылаетесь, касается переменных-членов, а не функций-членов. Вы подразумеваете, что функции-члены следуют тем же правилам? Во-первых, gcc 4.4.3 не ругается, если я переключаю порядок объявлений arr_ и fill_arr(), и выдает предупреждения, если порядок в списке инициализации не совпадает с порядком объявлений. - person ev-br; 24.06.2012
comment
@Zhenya 1-я часть ответа sbi (stackoverflow.com/a/3899583/981787) предназначена для функций-членов. - person Eight; 24.06.2012
comment
Ну, есть и его комментарий к его ответу... (в любом случае +1 за ссылку.) - person ev-br; 24.06.2012