我们有空的基类优化。看看这两种情况:
案例A
struct Empty1 { };
struct Empty2 { };
struct One: Empty1, Empty2 { };
此处sizeof(One)
为1. Empty1
和Empty2
的地址相同。
案例B
struct Empty { };
struct Empty1: public Empty { };
struct Empty2: public Empty { };
struct Two: Empty1, Empty2 { };
此处sizeof(Two)
为2. Empty1
和Empty2
的地址不同,因为它们都有Empty
(并且这些Empty
应该有所不同地址)。
为什么标准允许为不同类型使用相同的地址,但不允许使用相同的类型?这个规则避免了什么问题?
如果我创建一个tuple
实现,其中所有空成员将具有相同的地址(无论其类型),我将遇到什么问题?
答案 0 :(得分:3)
地址是对象身份的一部分。具有单独地址的相同类型的单独对象是一般规则。这就是你如何知道有多个对象。
在复制构造函数中,您经常可以找到自我赋值if (this != &other)
的测试。如果相同类型的不同对象具有相同的地址,则会失败。
无论如何都不能比较不同类型的物体,所以不是问题。我们还有一个struct及其第一个成员和一个数组,以及第一个拥有相同地址的元素,但它们的类型不同。
空基类在这里提出了一个问题,但前提是你有两个相同类型的基类,或者基类碰巧与派生类的第一个成员属于同一类型。因此,在这些情况下,有一些特殊规则禁止两个相同对象重叠。
这个想法是它们应该是两个独立的子对象,并且在this != &that
测试中工作。
答案 1 :(得分:1)
规则在标准[intro.object]中说明:
除非对象是零字段或零大小的基类子对象,否则该对象的地址是地址 它占据的第一个字节。两个对象a和b具有重叠的生命周期,而不是位字段可能具有 如果一个嵌套在另一个中,或者如果至少有一个是零大小的基类子对象,则为相同的地址 它们有不同的类型;否则,他们有不同的地址。
空基类落入此规则的一个原因是因为 可以将空基类引用转换为基础对象的引用。
最好是看到它在行动,我已经添加了由gcc生成的程序集-O3优化:
struct Empty1 { };
struct Empty2 { };
struct One: Empty1, Empty2 {
int i;
};
struct Other{
int i;
};
//an Empty and a One may have the same address
int f(Empty1& a,One& b){ mov DWORD PTR [rsi], 12 //write to *rsi
b.i=12; mov DWORD PTR [rdi], 15 //may be rsi==rdi
auto& a_one = mov eax, DWORD PTR [rsi] //reload from *rsi
static_cast<One&>(a); ret
a_one.i=15;
return b.i;
}
//an int and a One may have the same address
int f(int& a,One& b){ mov DWORD PTR [rsi], 12 //write to *rsi
b.i=12; mov DWORD PTR [rdi], 15 //may be rsi==rdi
a=15; mov eax, DWORD PTR [rsi] //reload from *rsi
return b.i; ret
}
//a long can not have the same address as a One
int f(long& a,One& b){ mov DWORD PTR [rsi], 12
b.i=12; mov eax, 12 //aliasing optimization
a=15; mov QWORD PTR [rdi], 15 //sure rsi!=rdi aliasing rule
return b.i; ret
}
//the int inside and Other can alias an int inside a One
int f(Other& a,One& b){ mov DWORD PTR [rsi], 12
b.i=12; mov eax, 12 //aliasing optimization
a.i=15; mov QWORD PTR [rdi], 15 //sure rsi!=rdi aliasing rule
return b.i; ret
}
给定地址只能存在一个完整对象。完整的对象是没有嵌套在另一个对象中的对象。
不可能成功地使用相同类型对同一地址(没有UB)进行对象。但是由于您的对象是空的,因此在优化的元组中不需要多个对象。您只需要实现一个get<I>
,该Is
引用所有{{1}}的同一个对象,它们是指同一个空类的对象。