Порядок инициализации в классе по сравнению со списком инициализации конструктора

Я хочу инициализировать группу членов в классе, чтобы исходный файл был чище. Однако объекты принимают аргумент, который я получаю только через конструктор, и могут инициализироваться либо в списке инициализации конструктора, либо в конструкторе через присваивание. (Второй вариант, конечно, не сработает.) Это в основном сценарий:

В заголовке

class Foo
{

public:
    Foo(Pointer * ptr);

private:

    Pointer * ptr;
    Member m1{ptr, "SomeText"};
    Member m2{ptr, "SomeOtherText"};
}

В CPP

Foo::Foo(Pointer*ptr) : 
    ptr(ptr) 
{
    // ...
}   

Теперь вопрос: говорит ли стандарт что-нибудь о порядке инициализации между ptr и m1/m2? Очевидно, этот код будет работать только тогда, когда ptr инициализируется до m1 и m2.


person ruhig brauner    schedule 07.09.2018    source источник


Ответы (3)


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

[class.base.init]#13.3

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

[ Примечание. Порядок объявления гарантирует, что базовые подобъекты и подобъекты-члены уничтожаются в порядке, обратном инициализации. — конец примечания ]

Это означает, что порядок инициализации всегда будет ptr -> m1 -> m2.

person songyuanyao    schedule 07.09.2018
comment
Красиво, это именно та ссылка, которую я искал. Спасибо! - person ruhig brauner; 07.09.2018

Порядок в определении класса важен и диктует порядок инициализации. Нет никакого способа избежать этого порядка, кроме как переопределить ваш класс (т.е. поменять местами порядок).

Оказавшись внутри тела конструктора, вы можете присвоить значение любой неконстантной переменной-члену с любым значением, которое вы хотите, но на тот момент они уже были инициализированы. Если вы хотите инициализировать элемент до этого, вы должны сделать это перед телом конструктора, т. е. использовать либо Foo::Foo(Pointer * ptr) : ptr(ptr) {}, либо инициализировать их, как вы делаете с m1 и m2.

person Clearer    schedule 07.09.2018
comment
Вы не можете переопределять переменные в C++. Вы можете назначить их, хотя. - person Lightness Races in Orbit; 07.09.2018
comment
@LightnessRacesinOrbit спасибо - теперь должно быть лучше. - person Clearer; 07.09.2018
comment
да, это наис - person Lightness Races in Orbit; 07.09.2018
comment
К сожалению, это на самом деле не отвечает на вопрос, но, тем не менее, содержит точную информацию. - person Lightness Races in Orbit; 07.09.2018
comment
@LightnessRacesinOrbit Это не так. Я хотел прокомментировать ваш ответ, но, поскольку он оказался длиннее вашего ответа, я решил вместо этого опубликовать его как ответ. - person Clearer; 12.09.2018
comment
К сожалению, мой ответ был плохим: P - person Lightness Races in Orbit; 12.09.2018

Это стандартное определение. Члены инициализируются в порядке объявления внутри класса, поэтому ваш код полностью действителен. Потенциальная опасность заключается в несовместимом порядке инициализации в конструкторе с порядком членов - тогда все равно поля инициализируются в порядке объявления.

person bartop    schedule 07.09.2018