C++静态变量初始化顺序造成的智能指针困惑

【2011-04-30 11:59:11记录于新浪博客,转载】

昨天在做项目测试时突然发现一个莫名异常。异常的现象很奇怪,表现在我的SQLite数据库更新时报死锁异常。

从数据库的死锁,你能想到什么?虽然缺乏充分理由,我还是首先怀疑是更新数据格式的问题,可是测试到半夜,没发现任何问题。今天早上进一步思考:数据库的死锁要有死锁条件,google结果是,SQLite容易在多进程并发时死锁。多进程?哪里出来的多进程?

进一步检查数据库操作。我的数据库操作封装在一个singleton单例类中,并通过c++的auto_ptr实现。所有的数据库操作都通过这个唯一接口进出。

static std::auto_ptr<CDBClass> m_hInstance;
static CDBClass* CDBClass::getInstance()
{
    if (m_hInstance.get() == 0) {
        m_hInstance = std::auto_ptr<CDBClass>(new CDBClass()); (1)
    }

    return m_hInstance.get();
}
数据库的连接在CDBClass的构造函数中实现。
CDBClass::CDBClass()
{
    m_db.open();
    ……
}

在项目其它代码中通过以下代码引用:
CDBClass* dbclass = CDBClass::getInstance(); (2)

根据SQLite死锁条件的分析,出现死锁的最大可能是试图对已打开数据库再次执行连接操作。可是,数据库的操作是单例模式,数据库连接操作所在的构造函数只应该被执行一次才对。

经过代码调试,发现代码(1)被先后调用了两次。也就是说,CDBClass的静态变量m_hInstance并没有保证唯一性,在系统执行过程中,它发生了一些奇怪的变化。

通过断点处的调用堆栈,发现第一次的代码(1)调用,发生在类A的构造函数中,而类A被定义为一个全局变量。这很正常,因为全局变量就是在第一时间内初始化的。可这些,又有什么关系呢?反复的思考所有可能的调用路径,想的脑袋都疼,依然百思不得其解。问题的焦点在于,m_hInstance在第一次初始化之后,其持有的模板指针怎么突然没了?

一个念头突然闪过,m_hInstance是个静态变量,其初始化过程也是发生在第一时间,它的初始化也会导致模板指针为空。难道,它的初始化发生在全局变量类A之后?赶紧调试,跟踪m_hInstance的初始化。

结果果真如此。

全局类A的初始化,先于静态变量m_hInstance发生。所以,当A实例化了时,m_hInstance先持有了模板类的指针;随后,m_hInstnace自身的初始化又把这个指针置为空,这也就是为什么代码(1)被又一次执行的原因。

解决办法:
在A的构造函数中移除对CDBClass::getInstance()的调用,问题解决。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值