在C ++

时间:2018-04-01 01:02:09

标签: c++ unions memory-alignment bit-fields

我可以假设2个结合起来的两个结构中具有相同类型的最多第一个字段是相同的吗?

我想创建容器类,如果它们很小或者将它们保存在向量中,它们会将一些元素保留在堆栈中。这就像小字符串优化。

我将其开发为类似联合的类,如下所述:http://en.cppreference.com/w/cpp/language/union

我使用bitfield作为类型标志:

#include <iostream>
#include <vector>

struct C {
  bool is_on_stack : 1;
  struct stack_data {
    size_t size : 3;
    int data[(sizeof(std::vector<int>)) / sizeof(int)];
    stack_data() : size(0) {}
  };

  struct heap_data {
    std::vector<int> data;
    heap_data() : data() {}
  };

  union {
    stack_data stack;
    heap_data heap;
  };
  C():stack() {}
  ~C() {
      if(!is_on_stack){
          heap.~heap_data();
      }
  }
};
int main() {
  std::cout << sizeof(C) << "\n";
  std::cout << sizeof(C::stack_data) << "\n";
  std::cout << sizeof(C::heap_data) << "\n";
}

问题是当sizeof stack_data为32且sizeof heap_data由于对齐而为24时,sizeof(C)为40。我在一个字段上花了额外的8个字节!

我发现将标志移动到结构定义中会使所有三种类型的大小等于32(没有任何额外的标记内存)

union C {
  struct stack_data {
    bool is_on_stack : 1;
    size_t size : 3;
    int data[(sizeof(std::vector<int>)) / sizeof(int)];
    stack_data() : size(0) {}
  } stack;

  struct heap_data {
    bool is_on_stack : 1;
    std::vector<int> data;
    heap_data() : data() {}
  } heap;
};

所以我想知道我可以确定c.stack_data.is_on_stack始终与c.heap_data.is_on_stack相同吗? 即使stack_data.is_on_stack状态下的实际联合没有任何损坏,我是否可以始终使用heap

1 个答案:

答案 0 :(得分:1)

我拉了相关位:

C ++ 14标准,第9章,第7点:

  

M(X)定义如下:

     
      
  • 如果X是非联合类类型,如果X没有非静态数据成员,则集合M(X)为空;   否则,它由X的第一个非静态数据成员的类型(其中所述成员可以是匿名联合),X0和M(X0)的元素组成。
  •   
  • 如果X是联合类型,则集合M(X)是所有M(Ui)和包含所有Ui的集合的并集,其中每个Ui是第i个非静态的类型   X的数据成员。
  •   
  • 如果X是非类型,则集合M(X)为空。
  •   
     

[注意:M(X)是在标准布局类中保证在X中处于零偏移的所有非基类子对象的类型集。 - 结束注释] < / em>的

将此应用于你的工会,假设我读得很好,你会得到M(你的工会)是stackheapstack.is_on_stackheap.is_on_stack。也就是说,所有这些都保证在0偏移。

顺便说一句,我很可能只是在结构中添加一个普通的is_on_stack权限,这样你就可以在进入union之前检查它是的哪一个 - ed类型。虽然技术上相同,但可能更清晰地测试foo.is_on_stack而不是foo.heap.is_on_stack