高手进!C++作用域不同造成的智能指针困惑

tttk 2011-04-30 02:45:01
昨天在做项目测试时突然发现一个莫名异常。异常的现象很奇怪,表现在我的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)处,开始跟踪。

结果,红色跟踪条第二次出现在断点(1)处。这个结果出乎我的意料,但又似乎合情合理。通过检查调用堆栈,两次断点依次出现在两个不同类A和B的构造函数中,两个构造函数都是通过代码(2)来获取对CDBClass的引用,从而间接的导致两次数据库连接。

进一步检查两个类A和B的构造过程,发现了问题:
A类声明为系统内部变量,在系统执行时,通过代码进行实例化,并;
B类声明为全局变量,在系统执行时,由系统负责实例化。

也就是说,两个类的构造函数通过调用CDBClass的getInstance()函数,本意是想获得全局唯一的单实例,可结果竟然获得的是两个完全不同的对象。原因只是因为它们在不同的作用域中被初始化。
...全文
263 3 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
tttk 2011-04-30
  • 打赏
  • 举报
回复
真相大白:
罪魁祸首原来是CDBClass的静态成员变量:m_hInstance;
B类声明为全局变量,和静态变量m_hInstance处于同一作用域。因此,B和m_hInstance都是在系统运行前初始化。关键问题在于,它们的初始化顺序。跟踪发现,B先于m_hInstance初始化,那么当B在构造函数中给m_hInstance赋值之后,之后的m_hInstance的自初始化又把自身置为empty。

原来如此。

解决办法:
把代码(2)中B的构造函数中移到其他成员函数中,问题解决。
zhongbin104 2011-04-30
  • 打赏
  • 举报
回复
在群里看到留言,来捧场。发表自己观点。先说明,我对数据库操作不熟练!

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

return m_hInstance.get();
}
这里就定死程序里只有一个实例。
A、B类的构造函数都是用的同一实例。

m_db.open(); 之前先判断下数据库是否已经打开,要是打开就做其他处理,未打开就做打开处理。

献丑了!
tttk 2011-04-30
  • 打赏
  • 举报
回复
想获得合理解释,为什么会有这样的结果,具体原因是什么?

谢谢。

16,548

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • AIGC Browser
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧