C++中定义联合类型标志的最佳方法

C++中定义联合类型标志的最佳方法,c++,unions,memory-alignment,bit-fields,C++,Unions,Memory Alignment,Bit Fields,我是否可以假设两个结构中最早的两个字段类型相同,并且连接到union中的字段是相同的 我想创建一个容器类,它可以将一些元素保留在堆栈中(如果它很小的话),或者将它们保留在向量中。这就像是对小字符串的优化 我开发它就像这里描述的union类: 我使用位字段作为类型标志: #include <iostream> #include <vector> struct C { bool is_on_stack : 1; struct stack_data { siz

我是否可以假设两个结构中最早的两个字段类型相同,并且连接到union中的字段是相同的

我想创建一个容器类,它可以将一些元素保留在堆栈中(如果它很小的话),或者将它们保留在向量中。这就像是对小字符串的优化

我开发它就像这里描述的union类:

我使用位字段作为类型标志:

#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";
}
问题是,由于对齐,当stack_数据的sizeof为32,heap_数据的sizeof为24时,sizeofC为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\u data.is\u on\u stack总是和c.heap\u data.is\u on\u stack相同吗?
我是否可以始终使用stack_data.is_on_stack,即使实际并集处于堆状态而没有任何损坏?

我提取了相关位:

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

MX的定义如下:

如果X是非联合类类型,则如果X没有非静态数据成员,则集合MX为空; 否则,它包括X的第一个非静态数据成员的类型,其中所述成员可以是匿名联合X0,以及MX0的元素。 如果X是联合类型,则集合MX是所有MUi和包含所有Ui的集合的联合,其中每个Ui是第i个非静态Ui的类型 X的数据成员。 如果X是非类类型,则集合MX为空。 [注:MX是所有非基类子对象的类型集,这些子对象在标准布局类中保证在X中处于零偏移。-结束注]

把这个应用到你的联合体,假设我读得很好,你会得到你的联合体是stack,heap,stack.is_on_stack,heap.is_on_stack。也就是说,它们都保证为0偏移


顺便说一句,我可能只是在结构中添加一个简单的is_on_堆栈,这样您就可以在进入union-ed类型之前检查它是哪个。虽然技术上完全相同,但测试foo.is\u在\u堆栈上可能比测试foo.heap.is\u在\u堆栈上更干净。

您想实现什么?你为什么需要一个工会?如果容器大小小于t 1-2个元素,我会尝试消除堆内存分配。如果元素的数量非常少,我将把它们存储在向量的位置,如果元素的数量更多,我将用数组中的数据构造并初始化一个向量。这可以减少堆内存分配和释放。据我所知,一些std::string实现使用这种称为小字符串优化的技巧。向量的大小是24字节,所以我可以保留3个整数。如果有很多短向量和很少的长向量,这可以是一些优化。而且,正如我所知,结构成员的内存位置与它们定义的顺序相同。所以我想我的位标志对于union的两个变体必须在同一个位置,但我不确定。只要在两者之间没有访问说明符,顺序是有保证的,是的。我不知道填充,但因为它是第一个成员,所以应该可以。很好的解释,谢谢。然而,为了字节经济,我将在子结构中保留字段,并将getter方法添加到联合类型中;。所以它以foo.heap.is_on_stack和foo.stack.is_on_stack和foo.is_on_stack的形式存在。您既可以享受字节经济又可以直接访问。谢谢您的讲解!