在C++中定义联合类型标志的最佳方法
The best way to define union type flag in C++
我可以假设两个结构中具有相同类型的两个最前的字段是相同的吗?
我想创建容器类,如果某些元素很小,它将一些元素保留在堆栈中或将它们保留在矢量中。这就像小字符串优化。
我把它发展成类似工会的类,这里描述:http://en.cppreference.com/w/cpp/language/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";
}
问题是,由于对齐,当 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
一样吗? 即使实际工会处于heap
状态而没有任何腐败,我也可以随时使用stack_data.is_on_stack
吗?
我拉了相关的位:
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 中处于零偏移量。
将此应用于您的联合,假设我读得很好,您就会发现 M(您的联合)是stack
、heap
、stack.is_on_stack
、heap.is_on_stack
。也就是说,它们都保证处于 0 偏移量。
顺便说一句,我可能只是在结构中添加一个普通is_on_stack
,这样您就可以在进入union
-ed 类型之前检查它是什么。尽管技术上相同,但它可能是更干净的测试foo.is_on_stack
而不是foo.heap.is_on_stack
。
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- 在c代码之间共享数据的最佳方式
- 使用std::source_location报告错误的最佳实践
- 派生类销毁的最佳实践是什么
- 将寄存器设计成可由C和C++访问的外设的最佳实践
- 在两台机器之间进行时间戳的最佳c++chrono函数是什么
- 使用QQuickFramebufferObject时同步数据的最佳方式是什么
- 在C++中向零方向近似的最佳方法
- 使用不同的CRT将新的C++代码与旧的(二进制)组件隔离开来的最佳方法是什么
- 从嵌套在std::映射中的std::列表中删除元素的最佳方式
- 如果条件为TRUE(最佳方式?),则在do while循环中后置增量
- 检测win32服务创建和删除的最佳方法
- 在reactor中存储eventHandlers的最佳方式是什么
- 即使使用调试编译标志,表达式也是"optimized out"
- 在线程中等待标志的最佳方法
- C ++实现全局开关/标志以控制程序行为的最佳方法,而无需将类绑定到公共点
- 在C++中定义联合类型标志的最佳方法
- 使用opencv框架的目标C项目的最佳编译器标志