Не инициализируется поле класса
Можно ли инициализировать поле списка инициализаций с использованием методов этого класса?
Пример, что я имею в виду
class A{
public:
A(arg...) : a(foo(arg...){} //is used uninitialized
private:
int a;
int foo(arg...){
//код
}
}
Ответы (2 шт):
Можно если в методе foo
не будут использоваться неинициализированные члены класса A. Члены класса инициализируются в порядке объявления в классе (а не в порядке перечисления в списке инициализации).
Простой случай, метод foo
не использует члены класса, только аргумент:
class A {
public:
int a;
A(int x) : a(foo(x)) {}
private:
int foo(int x) { return 7 + x; }
};
int main() {
A variable = A(1);
cout<<variable.a<<endl; // 8 - OK!
return 0;
}
Всё будет хорошо, если порядок объявления переменных будет указан верно. Т.е. вы используете метод foo
, который вызывает только уже объявленные переменные. В этом примере сначала объявляется b
, затем a
. Инициализируем b
затем мы инициализируем a
через метод foo
, который использует переменную b
class A {
int b;
public:
int a;
A(int x) : a(foo(x)), b(7) {}
private:
int foo(int x) { return b + x; } // b объявлено до a, она будет проинициализирована и код выполнится успешно
};
int main() {
A variable = A(1);
cout<<variable.a<<endl; // 8 - ОК!
return 0;
}
Меняем порядок объявления, теперь сначала объявляется a
, затем b
. Так как b
не инициализирована, мы не знаем с чем сложится аргумент.
class A {
public:
int a;
int b;
A(int x) : b(7), a(foo(x)) {}
private:
int foo(int x) { return b + x; } // b не проинициализирована, так как она объявлена после int a, несмотря на порядок перечисления в списке инициализации
};
int main() {
A variable = A(1);
cout<<variable.a<<endl; // 1 или 8 или 834834 или что?
return 0;
}
Инициализировать можно, но чтобы не наступать на грабли в виде чтения неинициализированных членов, рекомендуется такие функции делать независимыми от (нестатических) членов класса. Для этого существуют static-функции.
Всё, что нужно сделать, это добавить ключевое слово static
:
static int foo(arg...) {
// код, который в принципе не может иметь доступа к нестатическим членам класса
}
Т.о. функция становится более чистой. Понятно, что можно и в параметрах передать какие-то неинициализированные члены, даже в списке инициализации конструктора. Но в этом случае место таких ошибок становится локализованным. Не нужно идти в код функции и контролировать, что там не появились зависимости от новых членов.