友人が「ベース」型の非基本クラス オブジェクトをクラス型オブジェクト「派生」にキャストする場合があります。「派生」は「ベース」の派生クラスであり、関数のみを追加しますが、データは追加しません。以下のコードでは、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
です。ただし、削除すると(友人のコードで実際にそうであるように)、GCC の出力アセンブラー コードはのリターン アクセスを最適化せず、メモリから値をリロードします。したがって、GCCで「動作」を呼び出す友人のコードは(彼が意図したように)、まだ未定義の動作をしていると思いますがb
a
B::x
a.a
g
g((B*)&a);
したがって、本質的に同じ 2 つのケースで、GCC は一方のケースを最適化し、もう一方のケースを最適化しません。合法的に指すことb
ができるからですか?それとも、GCC が実際のコードを壊したくないだけなのでしょうか?a
私は述べている答えをテストしました
B::x を削除すると、B は標準レイアウト クラスの 9p7 の要件を満たし、アクセスは完全に明確になります。これは、2 つの型がレイアウト互換である 9.2p17 であるためです。
2 つのレイアウト互換列挙型を使用
enum A : int { X, Y };
enum B : int { Z };
A a;
int g(B *b) {
a = Y;
*b = Z;
return a;
}
とがレイアウト互換 (7.2p8)であるにもかかわらず、のアセンブラ出力はではなくをg
返します。1
0
A
B
したがって、私のさらなる質問は(回答を引用して)次のとおりです。「まったく同じレイアウトを持つ2つのクラスは「ほぼ同じ」と見なされ、最適化から除外されます。」. 誰かがGCCまたはClangについてこれを証明できますか?