Singleton构造函数失败了c ++ - 可能是什么?

时间:2013-04-09 06:37:30

标签: c++ exception mfc singleton mutex

我实际上面临一个巨大的问题:我有一个单身人士课程。我的程序是一个多线程MFC,因此可以从不同的线程调用单例的构造函数。我用一个互斥锁包围了单例实例 - getter函数,以避免死锁和多个构造。下面的调用意味着函数在第一次直接失败。

该函数看起来像(LOG_MSG宏将给定的字符串记录到我的日志文件中):

MyClass& MyClass::singleton ()
{
    LOG_MSG("MyClass::singleton -> jump in");

    static CMutex oInitMutex;
    try
    {
        CSingleLock oSingleLock((CSyncObject *) &oInitMutex, TRUE);
        LOG_MSG("!!! SINGLETON LOCK OKAY !!!");
        static MyClass oMyClassInstance;
        LOG_MSG("!!! SINGLETON CONSTRUCTION OKAY !!!");
        return oMyClassInstance;
    }
    catch(...)
    {
        CString excMsg("Unexpected exception by creating MyClass singleton instance!");
        LOG_MSG(excMsg);
        throw excMsg;
    }
}

我已经想通了,单例对象的构造不会失败(因为我们得到了“!!! SINGLETON CONSTRUCTION OKAY !!!”消息)。

日志输出说:

09.04.2013 ;07:14:51:832;"MyClass::singleton -> jump in"
09.04.2013 ;07:14:51:841;"!!! SINGLETON LOCK OKAY !!!"
... (constructor logs => NOTHING unexpected in it!!! everything runs fine, as they must!!!)
09.04.2013 ;07:14:52:125;"!!! SINGLETON CONSTRUCTION OKAY !!!"
09.04.2013 ;07:14:52:170;"Unexpected exception by creating MyClass singleton instance!"

这意味着什么?何时返回语句会抛出异常?请帮我解决这个问题...

2 个答案:

答案 0 :(得分:6)

虽然这不能解答您的特定问题,但它仍然是您整体问题的解决方案:您根本不需要互斥锁 C ++ 11标准[stmt.dcl] §4指定(当谈论函数本地的static变量时):

  

如果控件在变量的同时进入声明   在初始化时,并发执行应等待完成   初始化。 88 如果控制重新进入声明   在初始化变量时递归地,行为是   未定义。

注88的地方是:

  

注88:实现不得引入任何死锁   执行初始化程序。

换句话说,编译器会为您引入同步;无需手动执行此操作。

答案 1 :(得分:1)

<强> SOLUTION:

  

我弄清楚了问题,这并不容易。为了从我的错误中吸取教训,我   将共享代码,导致失败。

     

在构造函数中,我以不正确的方式使用sscanf函数调用:

const char* sBuffer;
// some stuff here that fills the sBuffer up
sscanf(sBuffer, "%X %X %X %X", &tags_[0], &tags_[1], &tags_[2], &tags_[3]);
     

数组在单例类中定义为:

private:
    char tags_[4];
     

注意:格式代码可以唤醒特定类型的变量   写入数据。例如:在我的情况下,tags_数组应该   是一个整数数组而不是字符数组。自单身类以来   索引第2,第3和第4个元素后应存储tags_,   sscanf函数将写入未定义的内存位置,   关于静态类的数据会覆盖一些东西   然而,它引起了多次实例化:这可以通过以下方式避免   静音,但在这种情况下,互斥对象将被覆盖。   可以找到关于(s)scanf所需类型的更多信息herehere

<强>结论:

  

要聪明并且意识到使用C功能/低级别呼叫。付出很多   注意输入参数,不仅是它们的值,还有它们的类型   太。如果您按预期支持其他类型,则程序的行为将是   undefined,但你不会得到编译错误:很难找到   那个问题稍后。