现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

局部静态变量的初始化与异常

2012-09-03 19:31 工业·编程 ⁄ 共 1925字 ⁄ 字号 暂无评论
文章目录

1、问题

编程的过程中,思考了一个问题。当一个局部的静态变量使用一个函数的返回值初始化时,如果该函数抛出异常,那么,局部静态变量是否被定义成功,即,如果再次调用包含局部静态变量的函数,抛出异常的函数会不会再次被调用。

2、测试

就此问题,我写了如下的测试程序:

#include <iostream>
#include <iomanip>

int func()
{
    throw 100;
}
int TestStatic()
{
    static int i=func();
    return i;
}

int main(int argc, char * argv[])
{
    try
    {
        std::cout<<TestStatic()<<std::endl;
    }
    catch(int i)
    {
        std::cout<<"exc1:"<<i<<std::endl;
        try
        {
            std::cout<<"TestStatic:"<<TestStatic()<<std::endl;
        }
        catch(int i)
        {
            std::cout<<"exc2:"<<i<<std::endl;
        }
    }
    return 0;
}

3、结果

1、在VC9中:第二次调用TestStatic函数不再抛出异常,即,局部静态变量已经定义成功。

2、在gcc中:第二次调用TestStatic函数依旧抛出异常,即,局部静态变量没有定义成功,需要再次进入定义,实现真正的内存分配空间。

对于结果,我更欣赏GNU的方式!

不管喜欢那种方式,测试结果都告诉我们,这段代码并部具有可移植性。VC的方式,让我比较失望,因为,因此而失去了一个通用的编程技巧。然而,知道什么是错的,比知道什么是对的还要重要,难道不是吗?

4、背景与应用

有朋友会问,这样的问题,什么情况下会遇到?

我只用一个比较经典的例子来说明。略微熟悉设计模式的朋友都会知道Singleton模式。一般返回的都是一个具体类的实例。虽说一般情况下构造函数中不要抛出异常,但免不了在某些情况下,可能会抛出异常,尤其是在这种单实例模式的情形下,没有必要一定保持构造函数中一定不抛出异常(stl要求容器中的类的构造函数不要抛出异常),所以,在这种情况下,我们似乎会希望,如果构造不成功,客户函数捕获异常,并修复错误后,再次获得单实例时,希望能够再次进行初始化,而得到一个正确的单实例的引用。然而,在这种情况下,面对两个编译器的测试结果,这段代码并不具有可移植性。

如果,只是如果,GNU编译器的方式是一个规范的话,那么,我们在Singleton模式下,就无需判断返回的对象是否有效,如果发生异常,也无须在实现类中编写弥补的代码,只需要再次重新获得Singleton即可,可以简化代码。但,这只是如果。

5、补充

回复 scwinter:

多谢兄弟关注!刚才我测试了一下,启用和未启用异常展开语义,编译的结果是不一样的。又掌握了一个知识点!结果如下:
E:/temp/C++>cl test.cpp
用于 80x86 的 Microsoft (R) 32 位 C/C++ 优化编译器 15.00.30729.01 版
版权所有(C) Microsoft Corporation。保留所有权利。

test.cpp
C:/Program Files/Microsoft Visual Studio 9.0/VC/INCLUDE/xlocale(342) : warning C4530: 使用了 C++ 异常处理程序,但未启用展开语义。请指定 /EHsc
Microsoft (R) Incremental Linker Version 9.00.30729.01
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:test.exe
test.obj

E:/temp/C++>test
exc1:100
TestStatic:0

E:/temp/C++>cl test.cpp /EHsc
用于 80x86 的 Microsoft (R) 32 位 C/C++ 优化编译器 15.00.30729.01 版
版权所有(C) Microsoft Corporation。保留所有权利。

test.cpp
Microsoft (R) Incremental Linker Version 9.00.30729.01
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:test.exe
test.obj

E:/temp/C++>test
exc1:100
exc2:100

给我留言

留言无头像?