惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

N
News and Events Feed by Topic
D
DataBreaches.Net
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Recorded Future
Recorded Future
Y
Y Combinator Blog
C
Check Point Blog
Google DeepMind News
Google DeepMind News
M
MIT News - Artificial intelligence
小众软件
小众软件
F
Full Disclosure
S
SegmentFault 最新的问题
Blog — PlanetScale
Blog — PlanetScale
B
Blog RSS Feed
Martin Fowler
Martin Fowler
P
Proofpoint News Feed
博客园 - 司徒正美
量子位
The GitHub Blog
The GitHub Blog
T
The Blog of Author Tim Ferriss
T
Tenable Blog
P
Privacy International News Feed
T
The Exploit Database - CXSecurity.com
C
Cyber Attacks, Cyber Crime and Cyber Security
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
G
Google Developers Blog
P
Proofpoint News Feed
T
Threatpost
Know Your Adversary
Know Your Adversary
aimingoo的专栏
aimingoo的专栏
Latest news
Latest news
Security Latest
Security Latest
Cyberwarzone
Cyberwarzone
A
About on SuperTechFans
P
Palo Alto Networks Blog
Stack Overflow Blog
Stack Overflow Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
The Hacker News
The Hacker News
A
Arctic Wolf
AWS News Blog
AWS News Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
NISL@THU
NISL@THU
Last Week in AI
Last Week in AI
Hacker News - Newest:
Hacker News - Newest: "LLM"
Spread Privacy
Spread Privacy
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Application and Cybersecurity Blog
Application and Cybersecurity Blog
I
InfoQ
J
Java Code Geeks
H
Help Net Security

博客园 - 泉子

算法题:求一个序列S中所有包含T的子序列(distinct sub sequence) Django模板输出Dict所有Value的效率问题 笔记:LNK2001不代表链接器真的需要链接相关符号 Windows Restart Manager 重启管理器 advapi32.dll kernel32.dll 中的两套注册表API 使用GDI+保存带Alpha通道的图像(续) 使用GDI+保存带Alpha通道的图像 窗口销毁的相关函数与消息,ActiveX控件的销毁 为什么不能将ptr_fun(operator delete)传递给For_Each 两个数之间的最短路径问题 四年记——身在中小企业 C++ Const总结 [转载]怎样用VB编写.DLL动态链接库文件 Visual Studio 6.0编译PWLib1.12总结 在Windows上编译PWLib 金山词霸没落了么? SendInput模拟键盘输入的问题 数组变量在取地址时回归:不再是指针 创建用于非Visual C++工具的DLL——VB调用C++ DLL为何必须使用def文件 - 泉子
C/C++函数中局部对象的构造与析构时机
泉子 · 2011-05-19 · via 博客园 - 泉子

忘了什么时候起,脑子里就存在了这样的观点:

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;
}

相关的东西似乎还有一些,一时找不到,以后有时间再补充。