(转载请注明原创于潘多拉盒子)

构造函数和析构函数是C++中再熟悉不过的概念了,几乎每个了解一点C++的人都知道这两个概念是什么意思。一个对象的全部生命期中构造函数和析构函数执行的时机如下:

1. 为对象分配空间。这个空间可能是在栈上(函数内的局部变量),可能是在数据区(静态变量、全局变量),也可能分配在堆上(new出来的变量)。

2. 执行对象对应的构造函数。如果继承有父类或有成员对象,则先执行父类的构造函数和成员对象的构造函数。

3. 对象生命期内的各种成员函数调用。

4. 执行析构函数。和#2中构造的过程相反,先执行自身的析构函数,再执行父类和成员对象的析构函数。

5. 释放为对象分配的空间。这个过程与#1相反。

对象的整个生命期中构造函数和析构函数的执行是具有非常精确的镜像对称性,也就是说,构造过程(包括构造函数和继承类、成员对象的构造函数)中的各个构造操作和析构过程(包括构造函数、成员对象、成员对象的析构函数)完全对称。这个过程在《C++对象模型》中有详细的说明。

对于#1,对象占有的空间,包括对象直接占有的空间,其大小也就是sizeof操作符给出的对象大小。C++要求对象的大小在编译时确定,因此该大小是在对象定义时确定下来的。

考虑如下的一段代码:

std::vector<int> u(10);
std::vector<int> v(20);
memcpy(&v, &u, sizeof(u));

首先第一个问题是:sizeof(u)和sizeof(v) 哪个更大?我见过有一部分C++程序员认为sizeof(v)会更大,原因是v里面存着20个int型变量,而v中存着10个int型变量。实际上,u和v的sizeof运算结果是一样大的!具体的大小可能跟编译器有关,但在一种编译器下,它们的大小是完全相等的!因为它们的类型是相同的!

由此也就知道了第3行代码是有问题的,将两个vector的对象按地址和大小拷贝,虽然本身可以编译并运行,甚至编译器也不会报告警告!但是会导致v持有u在构造函数中从堆上分配的空间,一方面导致double free,另一方面会导致v原先持有的堆上分配的空间泄漏!

有趣的是,可以利用构造函数和析构函数执行的时机,去利用编译器产生一些非常智能的代码。这里有一些典型的应用,比如std::auto_ptr:

std::auto_ptr<Widget> widget = new Widget();
// 像指针一样使用widget
widget->foo();
(*widget).bar();
if (widget->invalid())
{
return false; // 会在析构widget对象时自动释放new出来的Widget
}
// 即使有exception抛出,widget也会自动析构
return true; // 尤其是有多个return的时候,威力更大。

我们经常在实际中使用线程锁,在每个return前面都释放锁实在是一件麻烦的事情,而且也不是异常安全的,如果利用构造函数和析构函数,则能比较好的解决这个问题:

#include <pthread.h>

class ScopedLock
{
public:
ScopedLock(pthread_mutex_t& lock) : _lock(&lock)
{
pthread_mutex_lock(_lock);
} ~ScopedLock()
{
pthread_mutex_unlock(_lock);
} private:
  pthread_lock_t* _lock;
}; // 用例
int needForSafety()
{
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
ScopedLock scopedLock(&lock); // 加锁 // throw an exception:自动解锁
// return 1: 自动解锁
// return 2: 自动解锁
// ……
}

构造函数和析构函数的这种特性,在实际中是很有用的。

C++的优秀特性3:构造函数和析构函数的更多相关文章

  1. C++的优秀特性6:智能指针

    (转载请注明原创于潘多拉盒子) 智能指针(Smart Pointer)是C++非常重要的特性.考虑如下一段使用简单指针(Plain Pointer)的代码: A* a = new A(); B* b ...

  2. 不可或缺 Windows Native (21) - C++: 继承, 组合, 派生类的构造函数和析构函数, 基类与派生类的转换, 子对象的实例化, 基类成员的隐藏(派生类成员覆盖基类成员)

    [源码下载] 不可或缺 Windows Native (21) - C++: 继承, 组合, 派生类的构造函数和析构函数, 基类与派生类的转换, 子对象的实例化, 基类成员的隐藏(派生类成员覆盖基类成 ...

  3. C++C++中构造函数与析构函数的调用顺序

    http://blog.csdn.net/xw13106209/article/details/6899370 1.参考文献 参考1: C++继承中构造函数.析构函数调用顺序及虚函数的动态绑定 参考2 ...

  4. C++-理解构造函数、析构函数执行顺序

    先初始化序列中的函数调用,如果基类构造函数为非引用传递,则引起参数的拷贝构造 再: 先类内的成员构造函数(拷贝/默认),再类的构造函数:先基类,再派生类: 本文主要说明对象创建时构造函数的执行顺序,对 ...

  5. C++的优秀特性2:inline 函数

    (转载请注明原创于潘多拉盒子) Inline函数是C++的一个很小的特性,在不计较效率的情况下,这个特性似乎可有可无.然而,C++天生是为最为广泛的应用场景设计的,因此,总会有关于效率的问题.其实,除 ...

  6. 构造函数与析构函数(construction undergoing)

    构造函数和析构函数 一.构造函数: 1.普通构造函数:在对象被创建时利用特定的值构造对象,将对象初始化到一个特定的状态. 特性:构造函数的函数名和类名相同:没有返回值:在对象被创建时被自动调用:如果有 ...

  7. C++构造函数和析构函数,以及构造函数特殊成员变量和函数的初始化

    body, table{font-family: 微软雅黑; font-size: 10pt} table{border-collapse: collapse; border: solid gray; ...

  8. C++(1)C++类四个默认函数---构造函数、析构函数、拷贝函数、赋值函数

    C++构造函数和析构函数 默认构造函数指不带参数或者所有参数都有缺省值的构造函数!!! (1)构造函数.析构函数与赋值函数 构造函数.析构函数与赋值函数是每个类最基本的函数.它们太普通以致让人容易麻痹 ...

  9. 转 C++构造函数、析构函数、虚函数之间的关系

    C++构造函数.析构函数.虚函数之间的关系 1. 如果我们定义了一个构造函数,编译器就不会再为我们生成默认构造函数了.2. 编译器生成的析构函数是非虚的,除非是一个子类,其父类有个虚析构,此时的函数虚 ...

随机推荐

  1. android定时三种方式

    一.采用Handler与线程的sleep(long)方法二.采用Handler的postDelayed(Runnable, long)方法三.采用Handler与timer及TimerTask结合的方 ...

  2. [转] C# TextBox、DataGrideView中的数据绑定

    Xavierr 原文 C#数据绑定——简单的文本框绑定.DataGridView 一.TextBox的数据绑定 经常写用一个TextBox显示某个对象,然后编辑之后再保存的程序.以前都是在TextBo ...

  3. [Everyday Mathematic]20150212 求 $(\cos x+2)(\sin x+1)$ 的最大值

    设 $$\bex t=\tan \frac{x}{2}, \eex$$ 则 $$\bex \cos x=\frac{1-t^2}{1+t^2},\quad \sin x=\frac{2t}{1+t^2 ...

  4. php codeigniter (CI) oracle 数据库配置-宋正河整理

    database.php 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 $active_group = 'default'; $active_record ...

  5. 精品手游《里奥的财富》高清版逆向移植家用机与PC平台(转)

    冒险动作游戏<里奥的财富>于去年10月登陆移动平台,曾荣获App Store“年度优秀游戏”.开发商宣布将推出其HD版本,近期会陆续登陆PS4.PC.MAC.Xbox One平台. 由瑞典 ...

  6. python中函数总结之装饰器闭包

    1.前言 函数也是一个对象,从而可以增加属性,使用句点来表示属性. 如果内部函数的定义包含了在外部函数中定义的对象的引用(外部对象可以是在外部函数之外),那么内部函数被称之为闭包. 2.装饰器 装饰器 ...

  7. spring实例化bean的方式

    1.使用类构造器实现实例化(bean的自身构造器) <bean id = "orderService" class="cn.itcast.OrderServiceB ...

  8. Python cookbook-读书笔记01

    1 数据结构和算法 1.1 Unpacking a sequence into separate variable(解包,赋值) >>> data = [ 'ACME', 50, 9 ...

  9. C/C++——C++变量的作用域与生命周期,C语言中变量的作用域和生命周期

    全局变量 作用域:全局作用域(全局变量只需在一个源文件中定义,就可以作用于所有的源文件.) 生命周期:程序运行期一直存在 引用方法:其他文件中要使用必须用extern 关键字声明要引用的全局变量. 内 ...

  10. phpcms的增删改查操作整理

    一.查 ①select($where = '', $data = '*', $limit = '', $order = '', $group = '', $key='') /** * 执行sql查询 ...