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

构造函数和析构函数是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. Eclipse无法识别小米2S手机

    某日,发现小米2S手机调试程序,发现Eclipse识别不出该硬件设备. 最后,确认小米2S系统升级后,会把开发者选项-USB调试选项默认关闭,打开即可. ----------------------补 ...

  2. MBTiles地图瓦片管理工具

    采用C#+GMap.NET+MBTiles数据库来实现. 具有以下功能: 1)  支持单个文件追加到mbtiles数据库. 2)  支持批量导入Google切片组织的地图瓦片. 3)  支持直接对MB ...

  3. 把raw目录下的几张照片存放到SD卡里面去

    try { //SD卡路径 String filename =android.os.Environment .getExternalStorageDirectory().getAbsolutePath ...

  4. php获取网站根目录

    php获取网站根目录方法一:<?phpdefine("WWWROOT",str_ireplace(str_replace("/","\\&quo ...

  5. Asp.Net 自定义控件实现图片的上传,浏览,删除功能

    4月的时候公司比较闲,就想着自己做点东西,其实主要是为了更加熟悉.Net,毕竟接触的时间不长,趁着有时间想提高提高.不过当我做到图片上传这个功能的时候,就有些停滞不前了,连续写了两天也达不到自己想要的 ...

  6. kali linux 一些工具及命令集1(搜集DNS信息)

    DNS信息收集 1.dnsdict6   用于查看ipv6的dns信息,国内很少ipv6,基本无用 2.dnsmap 收集dns信息,同类别还有dnsenum,dnswalk 使用dnsmap需先找到 ...

  7. ctype库试运行

    from ctypes import * msvcrt=cdll.msvcrt message_string="Hello world!\n" msvcrt.wprintf(&qu ...

  8. jquery自动将form表单封装成json的具体实现

    前端页面:<span style="font-size:14px;"> <form action="" method="post&q ...

  9. 进入appstore中指定的应用

    1.进入appstore中指定的应用 NSString *str = [NSString stringWithFormat:                           @"itms ...

  10. failback 和failover

    dubbo 和motan都有在注册中心中都有这个概念 Failover 失效转移通俗地说,即当A无法为客户服务时,系统能够自动地切换,使B能够及时地顶上继续为客户提供服务,且客户感觉不到这个为他提供服 ...