这是今天零系列对象和子对象系列中的第三个问题.标准明确暗示成员子对象不能具有零大小,而基类子对象可以.
struct X {}; //empty class, complete objects of class X have nonzero size
struct Y:X { char c; }; //Y's size may be 1
struct Z {X x; char c;}; //Z's size MUST be greater than 1
Run Code Online (Sandbox Code Playgroud)
为什么不允许零大小的成员子对象只是像零大小的基类子对象?
TIA
在Konrad的回答之后编辑:考虑以下示例:
struct X{};
struct D1:X{};
struct D2:D1, X {}; //D2 has 2 distinct subobjects of type X, can they both be 0 size and located at the same address?
Run Code Online (Sandbox Code Playgroud)
如果两个相同类型X的基类子对象(如我的示例中)可以位于同一地址,那么应该能够成员子对象.如果他们不能,那么编译器会特别处理这种情况,因此它可以特别处理Konrad的示例(请参阅下面的答案),如果同一类中有多个相同类型,则不允许零大小成员子对象.我哪里错了?
Kon*_*lph 10
为什么不允许零大小的成员子对象
因为相同类型的几个(子)对象可以具有相同的地址,这是标准禁止的:
struct X { virtual ~X() { /* Just so we can use typeid! */ } };
struct Y {
X a;
X b;
};
Y y;
// The standard requires that the following holds:
assert(typeid(y.a) != typeid(y.b) or &y.a != &y.b);
Run Code Online (Sandbox Code Playgroud)
这有点合乎逻辑:否则,这两个对象对于所有意图和目的都是相同的(因为对象的标识仅由其类型和内存地址决定)并且单独声明它们是没有意义的.
当然,编译器可以有条件地允许零大小的成员对象以及基类,但这会更复杂。无论类型如何,空基类优化始终适用。任何时候编译器看到从没有数据成员的类派生的类时,它都可以使用空基类优化。
按照 @Konrad Rudolphs 的示例,对于成员对象,它必须检查类型,验证该位置不存在相同类型的其他对象,然后可能应用您的优化。好吧,除非成员对象位于包含类的末尾。如果是这样,那么对象的“真实”(非零)大小将超出包含类的末尾,这也将是一个错误。在基类情况下永远不会发生这种情况,因为我们知道基类位于派生类的开头,并且派生类具有非零大小。
因此,这样的优化会更加复杂、更加微妙,并且更有可能以意想不到的方式出现故障。
我无法立即引用任何零大小成员对象肯定会崩溃的案例,但我也不相信它们不存在。我已经指出了基类情况下不存在的一些限制,并且很可能存在更多限制。所以问题是,语言应该允许多少复杂性和不确定性才能使一种很少有用的优化成为可能?
| 归档时间: |
|
| 查看次数: |
985 次 |
| 最近记录: |