为什么对基类子对象有限制?

时间:2014-09-13 13:41:19

标签: c++ types base-class

3.9 / 2:

  

对于任何对象(除了基类子对象)之外的任何对象   可复制类型T,无论对象是否包含有效的类型值   T,构成对象的底层字节(1.7)可以复制到   char或unsigned char的数组。

3.9 / 3:

  

对于任何简单的可复制类型T,如果指向T的两个指针指向   不同的T对象obj1和obj2,其中既不 obj1 也不 obj2是   基类子对象,如果构成obj1的基础字节(1.7)是   复制到obj2中,obj2随后应保持与obj1相同的值。

我正式理解这些规则,但我感兴趣的是这些限制的重点是什么?

2 个答案:

答案 0 :(得分:9)

基类子对象可能在派生类使用的末尾有填充。鉴于两个类,

struct A {
  int a;
  char b;
};
struct B : A {
  char c;
};

完全有可能是sizeof(A) == sizeof(B)。如果他们是平等的,那么如果你只是使用memcpy来复制A子对象,那么事情应该很明显:你将无法阻止阅读甚至覆盖{{1} }值。

您的实现可能会也可能不会重复使用这样的填充。设计填充重复使用的ABI的正当理由正是为了很好地处理那些错误地将c用于此类子对象的代码。

注释给出了一个空基类的例子。这是当前实现很可能重用基类字节的一种特殊情况,但它不是唯一允许的时间。

答案 1 :(得分:0)

这是一个由基类子对象和EBO引起的价值搞乱的例子:

#include <cassert>
#include <iostream>

struct Base {}; // empty class

struct Derived1 : Base {
public:    
    int i;
};

int main()
{
    // the size of any object of empty class type is at least 1
    assert(sizeof(Base) == 1);

    // empty base optimization applies
    assert(sizeof(Derived1) == sizeof(int));

    Base objBase;
    Derived1 objDerived;
    objDerived.i = 42;
    Base& refToobjDerived = objDerived;

    char buf[sizeof(Base)]; // 1

    std::memcpy(buf, &objBase, sizeof(Base)); // copy objBase to buf
    // might do something with buf..
    std::memcpy(&refToobjDerived, buf, sizeof(Base)); // EBO! I'm overwriting the int's value!

    std::cout << objDerived.i; // Screwed
}

Example

如果渲染基类non-trivially-copyable,则不会触及该值。

hvd突出显示的另一个问题可能在于基类末尾的附加填充,用于存储派生拥有的数据。