C++标准是否保证了没有虚拟成员函数的类类型的大小
Does the C++ standard make any guarantee for the size of class types with no virtual member functions?
我使用C++进行嵌入式编程。
假设我必须实现一个严格定义的(即逐字节)类类型,我可以在不改变该类型对象的字节级别的情况下向其添加构造函数和其他一些非虚拟方法吗?也就是说,我可以假设不会向其中添加任何额外的数据吗?
我认为RTTI已关闭。
我想确定C++标准是否定义了这一点。
是的,如果仅添加构造函数和/或非虚拟方法,则不会更改类的大小或布局,因为原始类和新类将是布局兼容的(9.2类成员[class.mem]#17),但只有当它们是标准布局类时。
标准布局类别定义为:
9类[class]
标准布局类是这样一个类:
--没有非标准布局类类型的非静态数据成员(或这种类型的阵列)或参考
--没有虚拟功能(10.3),也没有虚拟基类(10.1),
--对所有非静态数据具有相同的访问控制(第11条)成员,
--没有非标准布局基类,
--在派生最多的类中没有非静态数据成员,并且最多一个基类具有非静态数据成员,或者没有基类具有非静态数据成员的类,以及
--没有与第一个非静态数据类型相同的基类成员
不是
C++11对sizeof
:有这样的看法
[C++11: 5.3.5/2]:
[..]应用于引用或引用类型时,结果是引用类型的大小应用于类时,结果是该类对象中的字节数,包括在数组中放置该类型对象所需的任何填充最派生类的大小应大于零(1.8)。将sizeof
应用于基类子对象的结果是基类类型的大小。当应用于数组时,结果是数组中的字节总数。这意味着n元素的数组的大小是元素大小的n倍。
。。。仅此而已。它没有指定"在数组中放置该类型对象所需的条件"是什么意思,而是将其留给目标ABI。
安腾ABI最近从以前的家(grr)中消失了,如果我没记错的话,它确实提供了你想要的那种保证,但这与C++保证不同。一点也不一样。
您可以使用编译器特定的打包/对齐选项来处理数据成员。但虚拟功能带来的空间增加超出了您的控制范围。你不会期望为非虚拟功能添加任何空间,但这也不能"保证"。
您可以static_assert(sizeof T == x, "T needs to be x bytes wide")
来检测何时通过代码更改打破了某些假设。这是你能得到的最好的。
在C++03及以前的版本中,没有。在布局方面绝对没有保证。在C++11中,有布局兼容的概念,但我不确定它能走多远;我希望在类中添加非虚拟函数不会破坏布局兼容性。另一方面,您提到了嵌入式编程和关闭RTTI;您可能会依赖于许多其他由编译器保证的东西,而不是标准。(例如,关闭RTTI的能力。)考虑到这一点,我建议寻找编译器的保证。我怀疑大多数针对嵌入式系统的编译器都提供了它们生成的布局的详细描述,您可以从那里开始。
您可以从C++工作草案n32422011-02-28中获得此保证
9.2类成员
18如果两个标准布局结构(第9条)类型具有相同数量的非静态,则它们是布局兼容的数据成员和相应的非静态数据成员(按声明顺序)具有布局兼容类型(3.9)。
这只谈论数据成员,所以两个类
struct A {
int d1;
float d2;
void f();
};
struct B {
int e1;
float e2;
int g() const;
double h();
};
应与布局兼容。
对于什么是标准布局类
9类
7标准布局类是这样的类:
-没有非标准布局类(或此类类型的数组)或引用类型的非静态数据成员,
--没有虚拟函数(10.3)和虚拟基类(10.1),
--对所有非静态数据组成员具有相同的访问控制(第11条),
--没有非标准布局基类,
--在最派生的类中没有非静态数据成员,并且最多有一个基类非静态数据成员,或者没有具有非静态数据会员的基类,并且
-没有与第一个非静态数据员相同类型的基类。108
- 为什么在我的函数类型后使用引用运算符 (&) 允许我修改它返回的值?
- 来自 DLL 的函数调用 [表观调用的括号前面的表达式必须具有(指向-)函数类型]
- 是否有任何建议来统一函数类型限定符并简化可恶的函数类型?
- 关于 C++ 中的函数类型定义
- 用于检测函数类型是否为否的特征
- 函数类型参数的模板参数推导
- 标准对此指向成员函数类型模板参数有何说明?是我的代码有误,还是 MSVS 16.6 有问题?
- C++无效的函数类型转换
- STL 函数和函数类型与函数指针类型
- 如何将result_of与函数类型定义一起使用
- 将模板(没有规范)传递给 std::thread() 会出现错误:<未解析的重载函数类型>匹配错误
- C++ 编译错误:gnu_printf是无法识别的格式函数类型
- 专门用于"direct"函数类型(与函数指针类型相对)
- 将函数类型作为模板参数传递不会编译
- 通过参数传递 lambda(无函数类型模板)
- 如何在模板参数中分离函数类型返回类型和参数
- 为什么比较函数类型需要指定为模板参数?
- 带有限定符的函数类型定义用例
- 如何声明对函数类型的常量引用
- 非类型模板参数允许各种函数类型?