标签:
1 Point global; 2 3 Point foobar() 4 { 5 Point local; 6 Point *heap = new Point; 7 *heap = local; 8 // ... stuff ... 9 delete heap; 10 return local; 11 }L1,L5,L6表现出三种不同的对象产生方式:global内存配置,local内存配置和heap内存配置.L7把一个 class object指定给另一个,L10设定返回值,L9则明确地以 delete 运算符删除heap object.
typedef struct { float x, y, z; } Point;如果以C++来编译这段码,会发生什么事情?观念上,编译器会为Point声明一个trivial default constructor,一个trivial destructor,一个trivial copy constructor,以及一个trivial copy assignment operator.但实际上编译器会分析整个声明,并为它贴上Plain Of Data标签.
1 Point global;时,观念上Point的trivial constructor和destructor都会被产生并被调用,constructor在程序起始(startup)处被调用而destructor在程序的exit()处被调用(exit()由系统产生,放在main()结束之前).然而,事实上那些trivial members要不是没被定义,就是没被调用,程序的行为一如它在C中的表现一样.
Point *heap = new Point;会被转换为对 new 运算符(由library提供)的调用:
Point *heap = __new(sizeof(Point));再一次强调,并没有default constructor施行于 new 运算符所传回的Point object上.L7对此object有一个赋值(赋值,assign)操作,如果local曾被适当地初始化过,一切就没有问题.
7 *heap = local;事实上这一行会产生编译器警告如下:
warning,line 7: local is used before being initialized.观念上,这样的指定操作会触发trivial copy assignment operator进行拷贝搬运操作.然而实际上此object是一个Plain Of Data,所以赋值操作(assignment)将只是像C那样的纯粹位搬运操作,L9执行一个 delete 操作:
9 delete heap;会被转换为对 delete 运算符(由libraray提供)的调用:
__delete(heap);观念上,这样的操作会触发Point的trivial destructor.但destructor要不是没有被产生就是没有被调用.最后,函数以传值(by value)的方式将local当作返回值传回,这在观念上会触发trivial copy constructor,不过实际上 extern 操作只是一个简单的位拷贝操作,因为对象是一个Plain Of Data.
class Point { public: Point(float x = 0.0, float y = 0.0 float z = 0.0) : _x(x), _y(y), _z(z) {} // no copy constructor, copy operator or destructor defined ... private: float _x, _y, _z; };这个经过封装的Point class,其大小并没有改变,还是三个连续的float,是的,不论 private,public 存取层,或是member function的声明,都不会占用额外的对象空间.
Point global; // 实施Point::Point(0.0, 0.0, 0.0);现在有了default constructor作用于其上,由于global被定义在全局范畴中,其初始化操作将延迟到程序激活(startup)时才开始(详见6.1节)
void mumble() { Point local1 = {1.0, 1.0, 1.0}; Point local2; // 相当于一个inline expansion // explicit initialization 会稍微快一些 local2._x = 1.0; local2._y = 1.0; local2._z = 1.0; }local1的初始化操作会比local2的高效,因为当函数的activation recored被放进程序堆栈时,上述initialization list中的常量就可以被放进local1内存中.
{ Point local; }现在被附加上default Point constructor的 inline expansion:
{ // inline expansion of default constructor Point local; local._x = 0.0;local._y = 0.0;local._z = 0.0; }L6配置出一个heap Point object:
6 Point *heap = new Point;现在则被附加一个"对default Point constructor的有条件调用操作":
Point *heap = __new(sizeof(Point)); if (heap != 0) heap->Point::Point();然后才又被编译器进行 inline expansion操作,至于把heap指针指向local object:
7 *heap = local;则保持这简单的位拷贝操作,以传值方式传回local object,情况也是一样:
10 return local;L9删除heap所指的对象:
9 delete heap;该操作并不会导致destructor被调用,因为并没有明确地提供一个destructor函数实体.
class Point { public: Point(float x = 0.0, float y = 0.0) : _x(x), _y(y) {} // no destructor, copy constructor, or copy operator defined ... virtual float z(); protected: float _x, _y; };再一次强调,并没有定义一个copy constructor,copy operator,destructor.所有的members都以数值来存取,因此在程序层面的默认语意的下,行为良好.
Point *Point::Point(Point *this, float x, float y) : _x(x), _y(y) { // 设定object的virtual table pointer(vptr) this->__vptr_point = __vtbl__point; // 扩展member initialization list this->_x = x; this->_y = y; // 传回this对象 return this; }合成一个copy constructor和一个copy assignment operator,而且其操作不再是trivial(但implicit destructor仍然是trivial).如果一个Point object被初始化或以一个derived class object赋值,那么以位为基础(bitwise)操作可能给vptr带来非法设定.
// copy constructor的内部合成 inline Point* Point::Point(Point *this, const Point &rhs) { // 设定object的virtual table pointer(vptr) this->__vptr_Point = __vtbl__Point; // 将rhs坐标中的连续位拷贝到this对象,或是经由member assignment提供一个member ... return this; }编译器在优化状态可能会把object的连续内容拷贝到另一个object上,而不会实现一个精确地"以成员为基础"的赋值操作.C++ Standard要求编译器尽量延迟nontrivial memebrs的实际合成操作,直到真正遇到其使用场合为止.
1 Point global; 2 3 Point foobar() 4 { 5 Point local; 6 Point *heap = new Point; 7 *heap = local; 8 // ... stuff ... 9 delete heap; 10 return local; 11 }L1的global初始化操作,L6的heap初始化操作以及L9的heap删除操作,都还是和稍早的Point版本相同,然而L7的memberwise赋值操作:
*heap = local;很可能触发copy assignment operator的合成,以及其调用操作的一个 inline expansion(内部扩展);以 this 取代heap而以rhs取代local.
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:
原文地址:http://blog.csdn.net/yiranant/article/details/47448877