У меня есть случай, когда друг бросает объект не базового класса типа "Base" на объект типа класса "Производные", где "Derived" является производным классом "Base" и только добавляет функции, но нет данных. В приведенном ниже коде я добавил элемент данных x
к производному классу
struct A {
int a;
};
struct B : A {
// int x;
int x;
};
A a;
int g(B *b) {
a.a = 10;
b->a++;
return a.a;
}
При строгом анализе псевдонимов GCC (также Clang) всегда возвращает 10
, а не 11
, потому что b
никогда не может указывать на a
в четко определенном коде. Однако, если я удаляю B::x
(как это имеет место в коде моего друга), код ассемблера вывода GCC не оптимизирует обратный доступ a.a
и перезагружает значение из памяти. Итак, код моего друга, который называет g
"работает" на GCC (как он и предполагал), хотя я думаю, что он по-прежнему имеет поведение undefined
g((B*)&a);
Таким образом, по существу в тех же двух случаях GCC оптимизирует один случай и не оптимизирует другой случай. Это потому, что b
может юридически указывать на a
? Или это потому, что GCC просто хочет не нарушать реальный код?
Я протестировал ответ, в котором говорится
Если вы удалите B:: x, то B удовлетворяет требованиям в 9p7 для класса стандартного макета, и доступ становится совершенно определенным, потому что два типа являются совместимыми с макетами, 9.2p17.
С двумя совместимыми с макетами перечислениями
enum A : int { X, Y };
enum B : int { Z };
A a;
int g(B *b) {
a = Y;
*b = Z;
return a;
}
Выход ассемблера для g
возвращает 1
, а не 0
, хотя a
и b
совместимы с макетами (7.2p8).
Итак, мой дальнейший вопрос (цитирование ответа): "Два класса с точно такой же макет могут считаться" почти одинаковыми ", и они не учитываются при оптимизации.". Может ли кто-нибудь предоставить доказательство этому для GCC или Clang?