На самом деле ошибка сегментации происходит в другой программе, которую я пытался скомпилировать, что происходит из-за этого поведения.
Мой вопрос:
Это ошибка или моя вина?
Воспроизводится любым способом (даже если something
поле является закрытым или защищенным) и вот мой пример:
main.cc:
#include <iostream>
class Test {
public:
const char* something = "SOMETHING HERE!!!";
Test(const int& number) : Test(something, number) { }
// XXX: changed `something` to `_something` to make it different
Test(const char* _something, const int& number) {
std::cout << _something << std::endl;
std::cout << number << std::endl; }
~Test() { }
};
int main(int argc, char* argv[]) {
Test te1(345);
Test te2("asdasdad", 34523);
return 0;
}
И вот что происходит при компиляции с:
g++ main.cc -Os -o main
и работает с:
./main
выход:
pi@pi:~/ $ ./main
A"�~ <-- this is random
345
asdasdad
34523
Но когда я включаю оптимизацию с -O0
или же -O1
или же -O2
… вывод только новая строка:
pi@pi:~/ $ ./main
pi@pi:~/ $
Версия G ++:
pi@pi:~/ $ g++ --version
g++ (Raspbian 6.3.0-18+rpi1) 6.3.0 20170516
const char* something = "SOMETHING HERE!!!";
Инициализатор по умолчанию справа, как следует из его названия, используется, только если вы не предоставили явный инициализатор в списке инициализатора конструктора. Давайте посмотрим на ваши:
Test(const int& number) : Test(something, number) { }
Хорошо, мы делегируем другому конструктору. Этот другой конструктор выполнит полную инициализацию, поэтому инициализатор по умолчанию не используется. Но … мы передаем неинициализированное значение something
в качестве параметра.
Test(const char* _something, const int& number) { /* ... */ }
Ой-ой. Теперь мы пытаемся использовать значение _something
, который является копией something
, который является неопределенным. Неопределенное поведение и огонь.
Вы действительно не должны передавать значение члена класса в качестве параметра его конструктору, если у вас нет бесконечного запаса огнеупорных цыплят и яиц.
Требуемое поведение можно получить, поместив значение по умолчанию при вызове конструктора делегата:
Test(const int& number) : Test("SOMETHING HERE!!!", number) { }
… или сохраняя его в выделенной статической переменной:
static constexpr char *const defaultSomething = "SOMETHING HERE!!!";
Test(const int& number) : Test(defaultSomething, number) { }
Это ошибка или моя вина?
О, это твоя вина Инициализатор членов по умолчанию используется только для инициализации объекта-члена в не делегирующем конструкторе. В соответствии с [Class.base.init] / 9, Акцент мой:
В не делегирующем конструкторе, если данный потенциально сконструированный подобъект не обозначен как mem-initializer-id
(включая случай, когда нет mem-initializer-list, потому что
конструктор не имеет инициализатора ctor), то
- если объект является нестатическим элементом данных, который имеет инициализатор элемента по умолчанию, и […] объект инициализируется из его
инициализатор члена по умолчанию, как указано в [dcl.init];
Так something
не инициализируется при передаче его целевому конструктору. Ваша программа имеет неопределенное поведение и обанкротилась.