C++ 如果类型相同,则对象地址必须不同,但如果类型不同,则地址可以相同
我们有空的基类优化。看看这两种情况: 案例AC++ 如果类型相同,则对象地址必须不同,但如果类型不同,则地址可以相同,c++,C++,我们有空的基类优化。看看这两种情况: 案例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 { };
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
应该有不同的地址)
为什么标准允许不同类型使用相同的地址,但不允许相同类型使用相同的地址?这个规则避免了什么问题
如果我创建一个
元组实现,其中所有空成员将具有相同的地址(无论其类型如何)?地址是对象标识的一部分。具有单独地址的相同类型的单独对象是一条一般规则。这就是为什么你知道有不止一个物体
在复制构造函数中,如果(this!=&other)
,通常可以找到一个自赋值测试。如果相同类型的不同对象具有相同的地址,则此操作将失败
不同类型的对象无论如何都不能像这样进行比较,所以这不是问题。我们还有一个结构和它的第一个成员,还有一个数组和第一个元素,它们有相同的地址,但类型不同
空基类在这里会造成问题,但前提是您有两个相同类型的基类,或者该基类恰好与派生类的第一个成员的类型相同。因此,在这些情况下,有专门的规则禁止两个相同对象的重叠
其思想是,它们应该是两个独立的子对象,并在this!=&标准[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
}
struct Empty1{};
结构清空2{};
结构1:Empty1,Empty2{
int i;
};
结构其他{
int i;
};
//一个空的和一个可能有相同的地址
intf(空1&a,1&b){mov DWORD PTR[rsi],12//写入*rsi
b、 i=12;mov-DWORD PTR[rdi],15//可能是rsi==rdi
auto&a_one=mov eax,DWORD PTR[rsi]//从*rsi重新加载
静态铸造(a);翻新
a_1.i=15;
返回b.i;
}
//int和One可能具有相同的地址
intf(int&a,One&b){mov DWORD PTR[rsi],12//写入*rsi
b、 i=12;mov-DWORD PTR[rdi],15//可能是rsi==rdi
a=15;mov eax,DWORD PTR[rsi]//从*rsi重新加载
返回b.i;返回
}
//long的地址不能与long的地址相同
国际货币基金组织(长期、长期、长期和长期){mov DWORD PTR[rsi],12
b、 i=12;mov-eax,12//混叠优化
a=15;mov QWORD PTR[rdi],15//sure rsi!=rdi别名规则
返回b.i;返回
}
//int-inside和Other可以在一个内部别名一个int
int f(其他a、1和b){mov DWORD PTR[rsi],12
b、 i=12;mov-eax,12//混叠优化
a、 i=15;mov QWORD PTR[rdi],15//sure rsi!=rdi别名规则
返回b.i;返回
}
给定地址只能存在一个完整的对象。完整对象是未嵌套在另一个对象中的对象
必须在同一地址(没有UB)使用同一类型的对象是不可能成功的。但由于对象是空的,所以在优化的元组中不需要多个对象。您只需要实现一个get
,它为所有Is
引用同一个对象,这些对象都指向同一个空类的对象。在您的示例中,您讨论的是基类。在你关于元组成员的问题中。有两件事似乎很重要unrelated@ArtemyVysotsky当前位置有两个问题,我认为这两个问题高度相关(它们都是关于对象的地址相同)。而元组
通常是通过继承实现的,其中使用了EBO。我想说的是规则是从C继承的。您可能有空的数组
。所以sizeof不能是0
。谢谢你的回答!对于空类,赋值是一个空函数(因为它没有可复制的内容),不是吗?所以你不会在里面写身份测试,但会发生什么问题呢?由于类为空,没有非静态成员,因此似乎不需要使用self进行测试。@Jarod42-这是一个示例,说明您需要知道是否有一个或两个对象,并使用它们的地址进行测试。具有单独地址的相同类型的单独对象是一条一般规则。例如,如果无法区分基类和派生类的第一个成员,为什么要将它们区分开来?@BoPersson:“相同类型的独立对象具有独立的ad?”