Data Member 的布局

考察以下代码:

class Point3d
{
public:
    //...
private:
    float _x;
    static List<Point3d*> *freeList;
    float _y;
    static const int chunkSize = 250;
    float _z;
};

其中, nonstatic data members 在 class object 中的排列顺序和其被声明的顺序是一致的, 但是任何介入的 static data members 都不会被放进布局之中。static data members 都存放在程序的 data segment 中, 和个别的 class objects 无关。
C++ Standard 要求, 在同一个 access section (即 private, public, protected 等) 中,members 的排列只需符合较晚出现的 members 在 class object 中有着较高的地址这一条件即可。 也就是说, 各个 members 并不一定要连续排列(意味着中间可被其他区段分隔)。那么有什么会可能被插在中间呢? 第一种是为了对齐所填补的 bytes, 第二种就是编译器可能会合成一些内部使用的 data mambers, 以支持整个对象模型, vptr 就是这样的东西, 当前的所有编译器都把它安插在每一个内含 virtual function 的 class object 之内。而 vptr 又会被放在什么位置呢?传统上它被放在所有声明的 members 的最后, 但是有的编译器也把 class object 的最前端。 这是因为 C++ standard 秉承先前所说的“对于布局放任的态度”, 所以允许编译器吧内部产生的 members 自由放在任何位置上, 甚至放在那些被程序员声明的 members 之前。
当然, 既然是放任的态度, C++ standard 也允许编译器将多个 access sections 之中的 data members 自由排列, 不必在乎它们出现在 class 声明中的次序, 意味着形如:

class Point3d
{
public:
    //...
private:
    float _x;
    static List<Point3d*> *freeList;
private:
    float _y;
    static const int chunkSize = 250;
private:
    float _z;
};

实际上与前一段代的大小和组成是一样的, 我的理解就是, 只要你是搞革命的, 我们不管你是从哪来的。 而实际在编译器中, 编译器可以随意把 y 或 z 或什么其他东西放为第一个, 但似乎目前的编译器没人这么做。
编译器实际的处理都是把一个以上的 access section 连锁在一起, 依照声明的次序连成一个连续区块。 Access section 的多寡不会引起编译器的额外负担, 不管是在几个 sections 中 声明多个 members, 还是在一个一个 section 中声明全部的 members, 得到的 object 的大小都是一样的。
考察以下代码:

//接受两个 data members, 判断谁先出现在 class object 之中。
//如果两个 members 都是不同的 access sections 中的第一个被声明的
//此函数就可以判断哪一个 section 先出现
template< class class_type,
      class data_type1,
      class data_type2 >
char*
access_order(
    data_type1 class_type::*mem1,
    data_type2 class_type::*mem2 )
{
    assert(mem1 != mem2);
    return
        mem1 < mem2
            ?"member 1 occurs first"
            :"member 2 occurs first";
}

上述函数可以这样被调用:
access_order( &Point3d::_z, &Point3d::_y );
PS: 但是, 我在 vs2013 上运行这段代码没有成功, 显示的错误是 error C2296: “<”: 非法,左操作数包含“int Point3d::* ”类型
这就让人不淡定了, 希望如果有人看到这篇博客可以指点一二, 我先在这谢谢了!

时间: 2024-10-20 02:48:34

Data Member 的布局的相关文章

C++对象模型——Data Member的绑定(第三章)

3.1    Data Member的绑定 (The Binding of a Data Member) 考虑下面这段代码: // 某个foo.h头文件,从某处含入 extern float x; // 程序员的Point3d.h文件 class Point3d { public: Point3d(float, float, float); // 问题:被传回和被设定的x是哪一个x? float X() const { return x; } void X(float new_x) const

继承与 Data Member(2)

加上多态的情况如果我要处理一个坐标点, 而不在意这是一个 Point2d 或 Point3d 实例, 那么就需要在继承关系中提供一个 virtual function 接口: class Point2d { public: Point2d(float x = 0.0, float y = 0.0) :_x(x), _y(y){}; //x 和 y 的存取函数与前一个博客中相同 //由于对不同维度的点, 这些函数操作固定不变, 所以不必设为 virtual virtual float Z()(fl

指向 Data Member 的指针及相关的效率影响

指向 data member 的指针是一个颇有用处的语言特性, 特别是如果你需要详细调查 class members 的底层布局的话.这个调查可以帮助你决定 vptr 是放在尾端还是起始处. 另一个用途是可以用来决定 clas 中 access sections 的次序.考察以下代码, 其中有一个 virtual function, 一个 static data member, 以及三个坐标值: class Point3d { public: virtual ~Point3d(); //...

C++对象模型——&quot;继承&quot;与Data Member(第三章) .

3.4 "继承"与Data Member 在C++继承模型中,一个derived class object所表现出来的东西,是其自己的members加上其base class members的总和.至于derived class members和base class members的排列次序并未在C++ Standard中强制指定:理论上编译器可以自由安排.在大部分编译器上,base class members总是先出现,但属于 virtual base class的除外. 了解这种继

Data 语意学---Data member的存取效率

<深度探索C++对象模型> 对于data member来说,有两种情况 static data member数据 每一个static data member只有一个实体,存放在程序的data segment之中,无论以何种方式,无论类的继承关系如何复杂,存取路径都是非常直接 Nonstatic data members 直接存放在一个class object之中,是属于一个对象的,是需要一个叫做偏移量的值来索引的. 尤其是虚拟继承,虚拟继承将为"经由base class subobj

3.1 Data Member的绑定

文章开始提出了一段示例代码,并讨论了返回哪个x的问题.然后 a)   给出了我们普遍认为正确的回答,并肯定了这个想法: b)   提醒大家,这在以前的编译器实现中,并非正确. 在早期的实现中,首先绑定的是“全局变量x”.因为该class中的x的声明尚未可见.由此导致的就是“防御性编程风格”.总结起来,具体做法有两种. c)   将所有的data member的声明提前: d)   将内联函数的实现移至class的声明之外. 对于第一点,我们容易理解.因为变量的声明中,较晚的声明总是可以覆盖之前的

C++对象模型——Data Member的存取(第三章)

3.3    Data Member的存取 已知下面这段代码: Point3d origin; origin.x = 0.0; x的存取成本是什么? 答案视x和Point3d如何声明而定,x可能是个 static member,也可能是个nonstatic member.Point3d可能是个独立(非派生)的 class,也可能从另一个单一的base class 派生而来;虽然可能性,但它甚至可能是从多重继承或虚拟继承而来.下面数节将依次检验每一种可能性. 先看这样一个问题,如果有两个定义,or

Effective C# 学习笔记(原则一:始终能的使用属性(property),而不是可直接访问的Data Member)

原则一:始终能的使用属性(property),而不是可直接访问的Data Member    Always use properties instead of accessible data members. 为什么要使用属性: 1.Net的data binding只支持Property,而不支持public data member的访问 Data binding的目的就是把一个object的Property绑定到一个用户界面的control上,web control或者windows form

Data Member 的存取

考察以下代码: Point3d origin; origin.x = 0.0; 此例中 x 的存取成本是什么? 答案则是视 x 和 Pointd 而定(别打脸, 我知道这是废话). 具体的呢? 因为 x 可能是个 static member, 也可能是个 nonstiatic member; Point3d 可能是个独立的 class, 也可能是另一个 单一的class 派生而来:甚至可能是从多重继承或虚拟继承而来(请不要小看其他人的代码中的可能性, 你都很有可能不知道 C++ 还能这么写, 有