ОБНОВЛЕНИЕ: я не прошу людей попробовать это и посмотреть, работает ли для них код. Я спрашиваю, является ли шаблон кода допустимым для C ++, независимо от того, работает ли он для вас.
Я исследую то, что я считаю ошибкой в компиляторе IAR C ++ для процессоров Renesas RX. Примеры следующего шаблона кода иногда работают в моей небольшой встроенной системе, в других случаях он дает сбой во время инициализации parentRefToChildInstance
при переходе на адрес 0x00000000 (или поблизости; я также видел переход на 0x00000038). Для данной версии исходного кода поведение кажется согласованным между компиляциями, но если код нарушается кажущимися несущественными способами, иногда поведение переключается.
Законно ли иметь ссылки чистого виртуального родительского класса на статически выделенные объекты дочернего класса, или это незаконно, потому что порядок инициализации статически выделенных объектов не может быть гарантирован?
char aGlobalVar = 0;
struct parent
{
virtual ~parent() {}
virtual void method1() = 0;
};
struct child : public parent
{
child(int someValue) : m_someData(someValue) {}
virtual ~child() {}
virtual void method1() { ++aGlobalVar; }
int m_someData;
};
child childInstance(0x1234abcd);
parent &parentRefToChildInstance = childInstance;
В случаях, когда происходит сбой, объект дочернего класса не был создан в момент инициализации ссылки на родительский класс; Я подозреваю, что компилятор каким-то образом использует указатель vtable дочернего объекта для инициализации ссылки на родительский класс, хотя я не подтвердил это наверняка. Но я думал, что компилятор должен иметь возможность инициализировать ссылку, зная только тип объекта, на который он ссылается, и его адрес, которые должны быть известны во время компиляции и времени компоновки соответственно. Если это правда, то, похоже, не имеет значения, какой порядок childInstance
и parentRefToChildInstance
инициализируется.
Кроме того, мы по-прежнему ограничены C ++ 03, если это имеет значение.
Вот main()
в дополнение к приведенному выше коду ...
int main()
{
printf("aGlobalVar = %u\n", aGlobalVar);
childInstance.method1();
printf("aGlobalVar = %u\n", aGlobalVar);
parentRefToChildInstance.method1();
printf("aGlobalVar = %u\n", aGlobalVar);
}
Обычно я ожидал, что он напечатает это, а не выйдет из строя во время инициализации статического объекта (даже до запуска main()
):
aGlobalVar = 0
aGlobalVar = 1
aGlobalVar = 2
childInstance
является статическим объектом файла, аparentRefToChildInstance
определяется как статический член другого класса, объявленного в файле заголовка и определенного в том же файле, что иchildInstance
. И я знаю, о чем вы говорите, вы не можете зависеть от порядка инициализации статического объекта. Но в этом случае, я думаю, должно быть законным инициализировать ссылку для ссылки на объект, который еще не был создан. Поэтому я не думаю, что порядок инициализации должен иметь значение. - person phonetagger   schedule 24.08.2018childInstance
выделяется статически (некоторые могут назвать его глобальным объектом), он не будет уничтожен до выхода из программы. А сбой происходит еще до запускаmain()
, поэтому висячие ссылки не могут быть проблемой. - person phonetagger   schedule 24.08.2018parentRefToChildInstance
. Если я посмотрю на сборку и регистры процессора, он попытается перейти к 0x00000000 в точке, содержащей всего несколько инструкций в его инициализации. - person phonetagger   schedule 24.08.2018parentRefToChildInstance
осуществляется во время статической инициализации в другом модуле компиляции, и этот модуль компиляции выполняет код до того, какchildInstance
илиparentRefToChildInstance
прошли динамическую инициализацию. - person Ben Voigt   schedule 24.08.2018parentRefToChildInstance
. - person aschepler   schedule 24.08.2018parentRrefToChildInstance
, отладчик прерывает (во время инициализации статического объекта перед запускомmain()
) всего несколько инструкций до сбоя. - person phonetagger   schedule 24.08.2018parentRefToChildInstance
со статического члена данных на функцию, возвращающую ссылку. Тогда не будет его инициализации, которая может произойти в неподходящее время (хотя ее можно использовать до инициализацииchildInstance
). Вы можете исправить это, переместивchildInstance
в функцию как статический локальный объект. - person Ben Voigt   schedule 24.08.2018