C/C++函数中局部对象的构造与析构时机
2011-05-19 19:34
483 查看
忘了什么时候起,脑子里就存在了这样的观点:
1. 局部变量应尽量定义在代码起始处
2. 局部变量的构造是在进入函数时进行的,其时间与局部变量声明的位置无关
我记得这个观点应该来自权威的书籍或某些具有丰富经验,在我看来就如同凡人眼里手持法杖、身着华服的法师一般神圣的开发大牛。这个观点在当时我的看来是如此的权威,以至于素爱折腾的我也在整个大学期间未予质疑。
由于这个特性,我一直以来就有一个疑问,在RAII中,为了保证Critical Section的最小化,岂不是得为此做刻意的函数分割,将Critical Section抽离出来用单独的函数包装。
不过,最近我在看log4cplus的代码时,看到如下的代码段:
这段代码让我对在我脑海里存在了长久时间的观点产生了质疑,如果那是对的,那这里何必用do循环来制造一个子域呢?因此我写了一些代码测试一下:
这段程序在VC6上的输出如下:
Local Variable Initial Test Function 1 : do{}
Begin of the loop body ...
obj construct ...
End of the loop body ...
obj destruct ...
Begin of the loop body ...
obj construct ...
End of the loop body ...
obj destruct ...
End of Function body 1
Local Variable Initial Test Function 2 : {}
Begin of the loop body ...
obj construct ...
End of the loop body ...
obj destruct ...
End of Function body 2
Local Variable Initial Test Function 3 : if{}
Begin of the loop body ...
obj construct ...
End of the loop body ...
obj destruct ...
End of Function body 3
Local Variable Initial Test Function 4 : no sub range
obj construct ...
End of Function body 4
obj destruct ...
obj construct ...
Local Variable Initial Test Function 5 : no sub range
End of Function body 5
obj destruct ...
从输出可以简单的得出一些结论:
1. 对象的构造时机取决于它的定义位置,初始化过程不会被编译器提前或延后。
2. 对象的析构在生命期结束(退出定义域)时由编译器自动执行。
3. 循环体内定义的变量会被初始化和析构多次。
4. 域以{}定义,它可以是函数体,do,while,if等复合语句,单独的{}也同样可以定义一个子域。
然而,这并非全部,我之前所接触到的说法不应该是空穴来说或是错觉,于是找了找,发现它其实来自C,在C语言中,所有的局部变量都必须定义在函数体的起始位置。创建一个.c文件,然后添加如下代码,该文件将编译失败。
相关的东西似乎还有一些,一时找不到,以后有时间再补充。
1. 局部变量应尽量定义在代码起始处
2. 局部变量的构造是在进入函数时进行的,其时间与局部变量声明的位置无关
我记得这个观点应该来自权威的书籍或某些具有丰富经验,在我看来就如同凡人眼里手持法杖、身着华服的法师一般神圣的开发大牛。这个观点在当时我的看来是如此的权威,以至于素爱折腾的我也在整个大学期间未予质疑。
由于这个特性,我一直以来就有一个疑问,在RAII中,为了保证Critical Section的最小化,岂不是得为此做刻意的函数分割,将Critical Section抽离出来用单独的函数包装。
不过,最近我在看log4cplus的代码时,看到如下的代码段:
do { ::log4cplus::thread::Guard _sync_guard_object(mutex); this->errorHandler = eh; } while (0)
这段代码让我对在我脑海里存在了长久时间的观点产生了质疑,如果那是对的,那这里何必用do循环来制造一个子域呢?因此我写了一些代码测试一下:
#include "stdafx.h" #include <iostream> using namespace std; #define mainSizeof main class obj { public: obj() { cout<<"obj construct ..."<<endl; } ~obj() { cout<<"obj destruct ..."<<endl; } }; void LocalVarIniTest1() { cout<<"Local Variable Initial Test Function 1 : do{} "<<endl; int i = 2; do { cout<<"Begin of the loop body ... "<<endl; obj o; cout<<"End of the loop body ..."<<endl; } while (--i); cout<<"End of Function body 1"<<endl<<endl; } void LocalVarIniTest2() { cout<<"Local Variable Initial Test Function 2 : {} "<<endl; { cout<<"Begin of the loop body ... "<<endl; obj o; cout<<"End of the loop body ..."<<endl; } cout<<"End of Function body 2"<<endl<<endl; } void LocalVarIniTest3() { cout<<"Local Variable Initial Test Function 3 : if{} "<<endl; if(true) { cout<<"Begin of the loop body ... "<<endl; obj o; cout<<"End of the loop body ..."<<endl; } cout<<"End of Function body 3"<<endl<<endl; } void LocalVarIniTest4() { cout<<"Local Variable Initial Test Function 4 : no sub range "<<endl; obj o; cout<<"End of Function body 4"<<endl<<endl; } void LocalVarIniTest5() { obj o; cout<<"Local Variable Initial Test Function 5 : no sub range "<<endl; cout<<"End of Function body 5"<<endl<<endl; } int mainLocalVarIni() { LocalVarIniTest1(); LocalVarIniTest2(); LocalVarIniTest3(); LocalVarIniTest4(); LocalVarIniTest5(); getchar(); return 1; }
这段程序在VC6上的输出如下:
Local Variable Initial Test Function 1 : do{}
Begin of the loop body ...
obj construct ...
End of the loop body ...
obj destruct ...
Begin of the loop body ...
obj construct ...
End of the loop body ...
obj destruct ...
End of Function body 1
Local Variable Initial Test Function 2 : {}
Begin of the loop body ...
obj construct ...
End of the loop body ...
obj destruct ...
End of Function body 2
Local Variable Initial Test Function 3 : if{}
Begin of the loop body ...
obj construct ...
End of the loop body ...
obj destruct ...
End of Function body 3
Local Variable Initial Test Function 4 : no sub range
obj construct ...
End of Function body 4
obj destruct ...
obj construct ...
Local Variable Initial Test Function 5 : no sub range
End of Function body 5
obj destruct ...
从输出可以简单的得出一些结论:
1. 对象的构造时机取决于它的定义位置,初始化过程不会被编译器提前或延后。
2. 对象的析构在生命期结束(退出定义域)时由编译器自动执行。
3. 循环体内定义的变量会被初始化和析构多次。
4. 域以{}定义,它可以是函数体,do,while,if等复合语句,单独的{}也同样可以定义一个子域。
然而,这并非全部,我之前所接触到的说法不应该是空穴来说或是错觉,于是找了找,发现它其实来自C,在C语言中,所有的局部变量都必须定义在函数体的起始位置。创建一个.c文件,然后添加如下代码,该文件将编译失败。
void fun() { int a; a = 1; int b; a = 2; b = 2; }
相关的东西似乎还有一些,一时找不到,以后有时间再补充。
相关文章推荐
- C++学习笔记之——局部对象和临时对象的构造和析构时机
- c++ 构造没完成 别的对象不能访问 析构时基类不要调用虚函数
- 为什么c++抛出异常后还能对函数内的局部对象进行析构? http://segmentfault.com/q/1010000002498987
- C++处理函数局部静态类对象的构造和析构
- 程序入口函数和glibc及C++全局构造和析构
- Self Summary: C++函数返回引用和指针的问题,局部对象与new对象的问题
- 一个有关C++中对象构造、析构和虚函数的问题
- 深度探索C++对象模型:5.构造、析构、拷贝语意学
- C++ 构造,析构顺序(静态对象)
- C++构造与析构(18) - 静态对象(static object)何时销毁
- 深入c++中临时对象的析构时机的详解
- 从汇编看c++中临时对象的析构时机
- Self Summary: C++函数返回引用和指针的问题,局部对象与new对象的问题
- 【C++】深度探索C++对象模型之构造、析构、拷贝语意学
- Self Summary: C++函数返回引用和指针的问题,局部对象与new对象的问题
- 类的构造,析构,临时对象与函数参数的关系
- C++----局部静态对象和函数
- 【C++】类和对象(构造与析构)
- C++对象的构造、赋值和析构
- C++手稿:对象的生命周期,构造与析构