假设我有两种类型A和B.
然后我做这个类型
struct Pair{
A a;
B b;
};
现在我有了这样的功能。
void function(Pair& pair);
我们假设function
只会使用该对中的a
部分。
然后是使用未定义的行为并以这种方式调用函数吗?
A a;
function(reinterpret_cast<Pair&>(a));
我知道编译器可以在成员之后插入填充字节,但是它也可以在第一个成员之前插入吗?
答案 0 :(得分:4)
我认为它是定义的行为,假设Pair
是标准布局。否则,它是未定义的行为。
首先,标准布局类及其第一个成员共享一个地址。 [basic.compound]中的新措辞(澄清了之前的规则)如下:
如果出现以下情况, a 和 b 两个对象指针可互换:
* [...]
* one是标准布局类对象,另一个是该对象的第一个非静态数据成员, 或者,[...]
* [...]
如果两个对象是指针可互换的,那么它们具有相同的地址,并且可以获得 通过reinterpret_cast
(5.2.10)指向另一个指针的指针。
同样来自[class.mem]:
如果标准布局类对象具有任何非静态数据成员,则其地址与地址相同 其第一个非静态数据成员。否则,其地址与其第一个基类的地址相同 子对象(如果有的话)。
所以从reinterpret_cast
到A
的{{1}}很好。如果Pair
只访问function
对象,那么该访问定义良好,因为a
的偏移量为0,所以行为等同于A
直接function
。显然,任何对A&
的访问都是不明确的。
然而,虽然我认为代码是定义的行为,但这不是一个好主意。它已定义的行为现在,但有一天某人可能会更改b
以引用function
,然后您就会陷入痛苦的世界。简单地写一下就容易多了:
pair.b
并直接使用void function(A& a) { ... }
void function(Pair& p) { function(p.a); }
致电function
。
答案 1 :(得分:-1)
是的,它是未定义的行为。
在结构对中,a和b之间可以有填充。对结构成员的赋值可以修改结构中的任何填充。所以对pair.a的赋值可以修改内存,它认为结构中有填充,实际上只有随机内存跟随你占用的内存。