在另一个翻译单元的静态破坏阶段引用时,“魔术静态”单例崩溃

Posted

技术标签:

【中文标题】在另一个翻译单元的静态破坏阶段引用时,“魔术静态”单例崩溃【英文标题】:"Magic static" singleton crashing when referenced in static destruction phase of another translation unit 【发布时间】:2014-07-17 18:58:18 【问题描述】:

我有一个简单的单例课程。我的singleton.h 文件看起来像这样:

class singleton

...
public:
    static singleton& instance();
;

我的singleton.cpp 看起来像这样:

...
singleton& singleton::instance()

    static singleton * const _instance(new singleton);
    return *_instance;

在编写这个类时,我认为我依赖于线程安全的函数局部静态初始化,我理解它在 C++ 标准的第 6.7 节中进行了描述,如here 所述。希望我明白这应该是如何工作的。

我正在使用 November 2013 CTP 工具链运行 Visual C++。微软表示,2013 年 11 月 CTP 支持线程安全的函数本地静态初始化,快速浏览编译器生成的目标代码表明它正在尝试这样做。

我的问题是销毁另一个翻译单元中的静态存储持续时间对象需要访问singleton::instance()。我预计这不会带来任何困难,因为支持singleton::instance() 的静态变量是一个永远不会被删除的指针。但是,从该其他对象调用 singleton::instance() 正在使我的进程崩溃,堆栈跟踪如下所示:

_Init_thread_header
singleton::instance
other_translation_unit_object::~other_translation_unit_object

其中_Init_thread_header() 似乎是由编译器插入以实现线程安全的静态初始化。

所以我的问题是:上面的代码是否表明我从根本上误解了静态初始化应该如何工作(很可能是这种情况,如果是这样的话,那就太好了:),还是可能有其他问题?

【问题讨论】:

这不是你的问题,但如果你不delete它,你的单例析构函数将永远不会运行。 虽然static singleton * const _instance 指向的实际对象在编写代码时永远不会被销毁,但对于编译器插入instance() 以保证其线程安全的任何_Init_thread_header() 内容可能并非如此初始化。我猜这是你的问题的根源,你有一个简单的静态析构函数顺序问题。 @0xbe5077ed 既然你使用的是 C++11,为什么不按照这里描述的简单方法来做单例:***.com/questions/11711920/… @0xbe5077ed 为什么不简单地static singleton _instance; return _instance;?? @0xbe5077ed - 也许你过度设计了这个。为什么不编写一个具有静态 instance 的简单函数并返回实例,类似于我评论中 SO 链接中概述的内容以及 πάντα ῥεῖ 建议的内容? 【参考方案1】:

在您使用的 Visual Studio 版本中未实现“Magic statics”。它们首先在 Visual Studio 2015 中实现。

https://msdn.microsoft.com/en-us/library/hh567368.aspx

【讨论】:

发帖者声称使用的是 VC++ 2013 年 11 月 CTP,它是比 Visual Studio 2013 中的编译器晚的编译器(但比 Visual Studio 2015 早的编译器)。他们发布的链接显示 2013 年 11 月的 CTP 应该支持“魔术静态”,而您发布的链接并没有说明任何一种方式。

以上是关于在另一个翻译单元的静态破坏阶段引用时,“魔术静态”单例崩溃的主要内容,如果未能解决你的问题,请参考以下文章

C# 我定义了一个静态类编译成DLL后,在另一个项目中引用这个DLL,但访问不了里面的成员

静态、全局和多个翻译单元

[翻译]为什么sys.setdefaultencoding()会破坏代码

Power Query,刷新时保持输出表相同大小

Excel中查找某个单元格中的内容在另一个表格中的位置

从多个编译单元引用模板化静态变量时,Clang 链接到不同位置