如何在 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 中允许单例构造函数重新进入/传递?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用工厂构造函数在 Dart 中实现单例模式?

单例的实现方式

VS2017社区中的C++程序崩溃

VS2017 MFC 类向导 - 如何像在 VS2015 中一样使用它

简单介绍如何使用PowerMock和Mockito来mock 1. 构造函数 2. 静态函数 3. 枚举实现的单例 4. 选择参数值做为函数的返回值(转)

为啥在 JavaScript 的 IF 语句中允许重新声明变量