如何在 VS2017 中允许单例构造函数重新进入/传递?
Posted
技术标签:
【中文标题】如何在 VS2017 中允许单例构造函数重新进入/传递?【英文标题】:How can I allow singleton constructor re-entry/pass-over in VS2017? 【发布时间】:2017-08-30 14:16:26 【问题描述】:我一直在将一些 c++ 应用程序从 Visual Studio 2013 移植到 Visual Studio 2017。除了我必须修复的大量新警告之外,编译和链接还不错。
但是,当运行应用程序时,它会在尝试重新进入单例的构造函数时“停止”(当连续的函数调用形成返回构造函数的循环时)。似乎这种行为在 VS2013 中是可以的,但在 VS2017 中不再有效。没有错误信息。
我知道所有与单例相关的坏事,并且至少不应该有循环。问题不存在。
有没有办法告诉 VS2017 编译器我想开枪打死自己,并允许与 VS2013 中相同的行为?
我无权访问导致此行为的代码,因为它来自第三方库,这就是为什么我不能“修复它”,很遗憾。
这是一个在 VS2013 中有效但在 VS2017 中无效的示例:
main.cpp
#include "Singleton.h";
int
main( void )
std::cout << "let's do this!" << std::endl;
int two = Singleton::GetReference().getTwo();
std::cout << "ok" << std::endl;
return 0;
单例.h
#pragma once
class Stuff;
class Singleton
public:
static Singleton& GetReference();
int getTwo() return 2;
private:
Singleton();
Stuff* stuff;
;
单例.cpp
#include "Singleton.h"
#include "Stuff.h"
Singleton&
Singleton::GetReference()
static Singleton theInstance;
return theInstance;
Singleton::Singleton()
stuff = new Stuff();
东西.h
#pragma once
class Stuff
public:
Stuff();
private:
int two;
;
Stuff.cpp
#include "Stuff.h"
#include "Singleton.h"
Stuff::Stuff()
two = Singleton::GetReference().getTwo();
在上面的代码中,一步步调试的时候,我们第一次上线static Singleton theInstance;
会按预期工作,但是第二次,一个F11会去文件thread_safe_statics.cpp
,进入方法extern "C" void __cdecl _Init_thread_header(int* const pOnce)
。 Shift+F11 将退出该方法,程序将在指定的行无限期等待(从调试器暂停程序时观察到)。
PS
这个问题也可能出现在 Visual Studio 2015 中,因为从接受的答案链接的文档提到了 VS2015。
【问题讨论】:
错误信息是什么? 你希望通过什么样的逻辑让单例从自己的构造函数中访问自己? 将 getTwo() 的访问权限从 Stuff::Stuff 的构造函数移至某个函数 init。实例构造完成后,在getInstance中使用call_once调用该函数,并将getTwo的值传递给它。 @VTT 如帖子中所述,我无权访问代码,它来自第三方库(在本例中为 OpenAL)。我知道这是一个非常糟糕的主意。 你可以访问哪一部分? 【参考方案1】:/Zc:threadSafeInit-
一般的“一致性”页面是MSDN: Conformance,其中详细说明了您可以禁用哪些新功能。
我需要 sizedDealloc 的代码,我的新编译器正在为一个库创建一个调整大小的新运算符,这打破了旧编译的预期。
由于这是一个编译标志,至少有一些代码在你的控制之下,你应该能够解开这个野兽。
构造函数Stuff::Stuff
正在对未完全构造的对象调用函数。
这会产生“未定义的行为”。如果直到构造函数结束才设置值“2”(例如)。
可能需要将 Singleton 拆分为 2 个,其中一个传递早期的静态数据(例如 2 个)。
第二个传递持有的对象 Stuff。东西只会依赖第一个,这会打破僵局。
另外,Stuff
的第二个构造函数告诉它要使用哪个对象,并从 Singleton::Singleton
调用
MSDN 文章禁用“Magic Statics”MSDN : disable threadsafe static initialization
【讨论】:
以上是关于如何在 VS2017 中允许单例构造函数重新进入/传递?的主要内容,如果未能解决你的问题,请参考以下文章
VS2017 MFC 类向导 - 如何像在 VS2015 中一样使用它
简单介绍如何使用PowerMock和Mockito来mock 1. 构造函数 2. 静态函数 3. 枚举实现的单例 4. 选择参数值做为函数的返回值(转)