C ++标准是否对没有虚拟成员函数的类类型的大小做出任何保证?

时间:2012-12-13 13:45:29

标签: c++

我使用C ++进行嵌入式编程。

假设我必须实现严格定义的(即逐字节)类类型,我可以向其中添加构造函数和其他一些非虚方法,而不会在字节级别更改该类型的对象吗?也就是说,我可以假设不会添加额外的数据吗?

我认为RTTI已关闭。

我想确定C ++标准是否定义了这个。

4 个答案:

答案 0 :(得分:8)

是的,如果添加构造函数和/或非虚拟方法,则不会更改类的大小或布局,因为原始类和新类将是布局兼容的( 9.2类成员[class.mem]#17),但仅当它们是标准布局类

标准布局类定义为:

  

9个班级[class]

     

标准布局类是一个类:

     

- 没有非标准布局类型的非静态数据成员(或   这类类型的数组)或参考,

     

- 没有虚函数(10.3),没有虚基类(10.1),

     

- 对所有非静态数据具有相同的访问控制(第11条)   成员,

     

- 没有非标准布局基类,

     

- 在派生程度最高的类中没有非静态数据成员   最多一个具有非静态数据成员的基类,或者没有基数   具有非静态数据成员的类,以及

     

- 没有与第一个非静态数据相同类型的基类   构件。

答案 1 :(得分:7)

不,不是真的。

C ++ 11对此有sizeof

  

[C++11: 5.3.5/2]: [..]当应用于引用或引用类型时,结果是引用类型的大小。 当应用于类时,结果是该类对象中的字节数,包括在数组中放置该类型对象所需的任何填充。最派生类的大小应更大比零(1.8)。将sizeof应用于基类子对象的结果是基类类型的大小。应用于数组时,结果是数组中的总字节数。这意味着 n 元素数组的大小 n 乘以元素的大小。

......就是这样。它没有指定“在数组中放置该类型的对象所需”的含义,而是将其留给目标ABI。

最近从its previous home(grr)消失的Itanium ABI确实提供了您正在寻找的那种保证,如果我没记错的话,但这与C ++保证不同。完全不一样。

您可以使用特定于编译器的打包/对齐选项来处理数据成员。但由于虚拟功能导致的空间增加是您无法控制的。您不希望为非虚函数添加任何空间,但这也不是“保证”。

每当您通过代码更改破坏某些假设时,您都可以static_assert(sizeof T == x, "T needs to be x bytes wide")进行检测。这是你能得到的最好的。

答案 2 :(得分:5)

在C ++ 03和之前,没有。绝对没有关于布局的保证。在C ++ 11中,存在布局兼容的概念,但我不确定它有多远;我希望希望在类中添加非虚函数不会破坏布局兼容性。另一方面,您提到嵌入式编程并关闭RTTI;你可能依赖于编译器保证的许多其他东西,而不是标准。 (例如,关闭RTTI的能力。)鉴于此,我建议寻找编译器的保证。我怀疑大多数针对嵌入式系统的编译器提供了他们生成的布局的详细描述,你可以从那里开始。

答案 3 :(得分:1)

您可以从 Working Draft C ++,n3242,2011-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