c++ - 对齐存储的 g++ 编译器问题 - 这是编译器错误吗?
问题描述
我从此链接复制了下面的程序
#include <iostream>
#include <type_traits>
struct A { // non-POD type
int avg;
A (int a, int b) : avg((a+b)/2) {}
};
typedef std::aligned_storage<sizeof(A),alignof(A)>::type A_pod;
int main() {
A_pod a,b;
new (&a) A (10,20);
b=a;
std::cout << reinterpret_cast<A&>(b).avg << std::endl;
return 0;
}
我在这段代码上运行了 gdb 以了解各种成分的大小,结果如下:
(gdb) b 18
Breakpoint 1 at 0x96d: /home/ripunjay/study/bitbucket/study/cpp/aligned_storage.cpp:18. (3 locations)
(gdb) r
Starting program: /home/ripunjay/study/bitbucket/study/cpp/aligned_storage
Breakpoint 1, _GLOBAL__sub_I_main () at aligned_storage.cpp:18
18 }
(gdb) ptype a
type = const union {
int i[2];
double d;
}
(gdb) ptype A_pod
type = union std::aligned_storage<4, 4>::type {
unsigned char __data[4];
struct {
<no data fields>
} __align;
}
(gdb) ptype A_
No symbol "A_" in current context.
(gdb) ptype A
type = struct A {
int avg;
public:
A(int, int);
}
(gdb) p sizeof(A)
$1 = 4
(gdb) p sizeof(a)
$2 = 8
(gdb) p sizeof(b)
$3 = 8
(gdb) ptype A
type = struct A {
int avg;
public:
A(int, int);
}
后来看到一个正常的构造函数调用,我在 main() 中添加了一行来构造一个对象 c,如下所示 -
int main() {
A_pod a,b;
A c(10,20);
new (&a) A (10,20);
b=a;
std::cout << reinterpret_cast<A&>(b).avg << std::endl;
return 0;
}
这导致 a 和 b 的大小甚至类型定义发生变化。令人惊讶的是,即使注释掉了这个新添加的行,编译器也会有不同的行为。
(gdb) r
Starting program: /home/ripunjay/study/bitbucket/study/cpp/aligned_storage
15
Breakpoint 1, main () at aligned_storage.cpp:18
18 return 0;
(gdb) ptype a
type = union std::aligned_storage<4, 4>::type {
unsigned char __data[4];
struct {
<no data fields>
} __align;
}
(gdb) ptype b
type = union std::aligned_storage<4, 4>::type {
unsigned char __data[4];
struct {
<no data fields>
} __align;
}
(gdb) ptype A_pod
type = union std::aligned_storage<4, 4>::type {
unsigned char __data[4];
struct {
<no data fields>
} __align;
}
g++ --version
g++ (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0 Copyright (C) 2017 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
解决方案
通过这样做,std::cout << reinterpret_cast<A&>(b).avg << std::endl;
您的程序会表现出未定义的行为。为什么?您使用未初始化的值。
这意味着什么?该编译器被允许做任何事情。我的意思是任何东西,包括炸毁你的电脑——这是标准允许的。因此,在 gdb 中看到类型大小/填充/对齐等方面的变化也就不足为奇了。编译器可以这样做,因为你进入了不羁的行为领域。
恕我直言,但由于您class A
更改的 UB 大小/对齐方式,没有简单的方法可以确定。因为它改变了被改变的内部std::aligned_storage
(因为对齐的存储内部对于不同的大小/对齐对可以有非常不同的内部表示)。
推荐阅读
- c# - 动态圆环网格生成中的角度已关闭
- sapui5 - SAPUI5 智能过滤栏区分大小写搜索
- css - Flex Box 列与行
- reactjs - React 应用程序构建在 Heroku 上损坏,但在本地工作
- php - 如何从 textarea 1 中删除不包含 textarea 2 中每一行的行?[PHP]
- java - 在没有迭代器的情况下从 O(1) 中的 LinkedList 中删除最后一个元素(java)
- angular - 在路由Angular之间切换时如何在组件之间传递对象
- android - 如何在拦截器中获取应用程序上下文
- range - 带有流插件的 Chartjs:更新 y 范围
- python - 不和谐音乐机器人