单例对象抛出ctor-再次访问?

Dea*_*ean 16 c++ memory-management exception unique-ptr

我可以使用C ++ 11或C ++ 14(甚至C ++ 17)。假设我有一个单例对象


class MyInstance {
public:
    MyInstance() {
        throw std::runtime_exception("something went wrong"); // Ctor might throw
    }
};

MyInstance& getInstance() {
    static MyInstance obj;
    return obj;
}
Run Code Online (Sandbox Code Playgroud)

现在,我确保对的每个调用getInstance都包装在

try {
    auto& inst = getInstance();
} catch(std::runtime_error& e) {
   // do something
}
Run Code Online (Sandbox Code Playgroud)

我现在想知道的是:如果在构造函数中初始化失败并在日志中抛出并捕获并通知用户后,程序try代码路径中传递并再次调用getInstance,会发生什么?

我做了一些猜测,但我不知道它们是否正确:

该对象具有静态存储,因此仅在我认为之后才会尝试构建它?返回对未构造对象的引用会得到悬挂的引用和未定义的行为吗?是否可以使用unique_ptras静态变量来obj解决此问题,以便我可以多次访问指针,还可以检查对象是否已正确构造(if (uptr == TRUE))?

Sto*_*ica 10

如果构造函数抛出该对象,则不会初始化。因此,如果控制权getInstance再次通过,初始化也将再次执行。

[stmt.dcl](重点是我的)

4在第一次控制通过其声明时,执行具有静态存储持续时间或线程存储持续时间的块范围变量的动态初始化。此类变量在初始化完成后即被初始化。如果初始化由于抛出异常而退出,则初始化未完成,因此下次控件进入声明时会再次尝试初始化。如果在初始化变量时控件同时输入了声明,则并发执行应等待初始化完成。如果控件在初始化变量时递归地重新输入声明,则该行为未定义。


Lig*_*ica 9

[stmt.dcl]/4:当控件第一次通过其声明时,将执行具有静态存储持续时间或线程存储持续时间的块范围变量的动态初始化。此类变量在初始化完成后即被初始化。如果初始化由于抛出异常而退出,则说明初始化未完成,因此下次控件进入声明时会再次尝试初始化。 [..]

无需“猜测”;你可以std::cout跟踪内MyInstance::MyInstance()并调用getInstance()两次

也不需要智能指针;对象存在还是不存在,并且在没有getInstance()对象存在的声明之后无法继续进行内部操作,因为您抛出了异常!

顺便说一句std::runtime_error,不是std::runtime_exception

  • 我在测试中做了“ cout”操作,但是随着UB的阴影潜伏,我认为这只是一个模拟实验。标准报价将其清除。 (3认同)