【问题标题】:Why there is a restriction for a base-class subobject?为什么对基类子对象有限制?
【发布时间】:2014-11-07 13:09:02
【问题描述】:

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 相同的值。

我正式了解这些规则,但我很感兴趣这些限制的意义何在?

【问题讨论】:

  • 可能是因为空基优化。
  • @T.C.这不是很清楚。能举个例子解释一下吗?
  • @DmitryFucintv 给定struct T {}; struct D : T { int x; };sizeof(T) == 1,但在D 中,基类子对象的大小可能为零。
  • 我相信 TC 有道理,我不知道 EBO 但听起来绝对是避免基类子对象的原因
  • @DmitryFucintv 这一个会导致问题的例子。使用memcpyT 子对象复制到另一个D 对象将覆盖x 的一个字节。

标签: c++ types base-class


【解决方案1】:

基类子对象的末尾可能有被派生类使用的填充。给定两个类,

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

sizeof(A) == sizeof(B) 完全有可能。如果它们相等,那么如果您只是使用memcpy 来复制A 子对象,则应该清楚事情会中断:您将无法阻止读取甚至覆盖c 值。

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

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

【讨论】:

    【解决方案2】:

    这是一个由于基类子对象和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 强调的另一个问题可能在于用于存储派生拥有的数据的基类末尾的额外填充。

    【讨论】:

      猜你喜欢
      • 2021-12-12
      • 2018-12-16
      • 1970-01-01
      • 1970-01-01
      • 2018-04-29
      • 1970-01-01
      • 2011-11-15
      • 2018-02-02
      • 1970-01-01
      相关资源
      最近更新 更多