Делегирующий конструктор дает ошибку сегментации при использовании поля класса для аргумента

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

Мой вопрос:

Это ошибка или моя вина?

Воспроизводится любым способом (даже если 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

11

Решение

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) { }
20

Другие решения

Это ошибка или моя вина?

О, это твоя вина Инициализатор членов по умолчанию используется только для инициализации объекта-члена в не делегирующем конструкторе. В соответствии с [Class.base.init] / 9, Акцент мой:

В не делегирующем конструкторе, если данный потенциально сконструированный подобъект не обозначен как mem-initializer-id
(включая случай, когда нет mem-initializer-list, потому что
конструктор не имеет инициализатора ctor), то

  • если объект является нестатическим элементом данных, который имеет инициализатор элемента по умолчанию, и […] объект инициализируется из его
    инициализатор члена по умолчанию, как указано в [dcl.init];

Так something не инициализируется при передаче его целевому конструктору. Ваша программа имеет неопределенное поведение и обанкротилась.

15

По вопросам рекламы [email protected]