简体   繁体   English

如何在VS2017中允许单例构造函数重新进入/传递?

[英]How can I allow singleton constructor re-entry/pass-over in VS2017?

I've been porting some c++ app from Visual Studio 2013 to Visual Studio 2017. Aside from the plethora of new warnings that I had to fix, the compilation and linking went okay. 我一直在将一些c ++应用程序从Visual Studio 2013移植到Visual Studio 2017.除了我必须解决的大量新警告之外,编译和链接也没问题。

However, when running the app, it 'stalled' when trying to re-enter the constructor of a singleton (when successive function calls form a loop back to the constructor). 但是,在运行应用程序时,它在尝试重新进入单例的构造函数时“停顿”(当连续的函数调用形成一个循环回到构造函数时)。 It seems that this behaviour was okay in VS2013, but is no longer valid in VS2017. 看来这种行为在VS2013中没问题,但在VS2017中不再有效。 There is no error message. 没有错误消息。

I'm aware of all the bad things related to singletons, and that there should at least not be loops. 我知道与单身人士有关的所有坏事,至少应该没有循环。 The question is not there. 问题不在那里。

Is there a way to tell the VS2017 compiler that I'd like to shoot myself in the foot, and allow the same behaviour that was there in VS2013? 有没有办法告诉VS2017编译器我想用脚射击自己,并允许VS2013中的相同行为?

I don't have access to the code that causes this behaviour because it comes from a third-party library, this is why I can't 'just fix it', unfortunately. 我无法访问导致此行为的代码,因为它来自第三方库,这就是为什么我不能“只是修复它”,不幸的是。

Here is an example which works in VS2013, but doesn't work in VS2017: 这是一个在VS2013中有效的示例,但在VS2017中不起作用:

main.cpp 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;
}

Singleton.h Singleton.h

#pragma once

class Stuff;

class Singleton
{
public:
  static Singleton& GetReference();

  int getTwo() { return 2; }

private:
  Singleton();

  Stuff* stuff;
};

Singleton.cpp Singleton.cpp

#include "Singleton.h"
#include "Stuff.h"

Singleton& 
Singleton::GetReference() { 
  static Singleton theInstance; 
  return theInstance; 
}

Singleton::Singleton()
{
  stuff = new Stuff();
}

Stuff.h Stuff.h

#pragma once

class Stuff
{
public:
  Stuff();
private:
  int two;
};

Stuff.cpp Stuff.cpp

#include "Stuff.h"
#include "Singleton.h"

Stuff::Stuff()
{ 
  two = Singleton::GetReference().getTwo();
}

In the code above, when step-by-step debugging, the first time we get on the line static Singleton theInstance; 在上面的代码中,当逐步调试时,我们第一次上线static Singleton theInstance; will work as expected, but the second time, a F11 will go to the file thread_safe_statics.cpp , into the method extern "C" void __cdecl _Init_thread_header(int* const pOnce) . 将按预期工作,但第二次, F11将转到文件thread_safe_statics.cpp ,进入方法extern "C" void __cdecl _Init_thread_header(int* const pOnce) A Shift+F11 will exit the method and the program will wait indefinitely at the line specified (observed when pausing the program from the debugger). Shift + F11将退出该方法,程序将在指定的行无限期地等待(从调试器暂停程序时观察)。


PS PS

This issue probably occurs in Visual Studio 2015 too, as the documentation linked from the accepted answer mentions VS2015. 此问题也可能发生在Visual Studio 2015中,因为从接受的答案链接的文档提到了VS2015。

/Zc:threadSafeInit-

The general "Conformance" page is MSDN: Conformance , which details which new features you can disable. 一般的“一致性”页面是MSDN:Conformance ,它详细说明了您可以禁用的新功能。

I needed the code for sizedDealloc, where my new compiler was creating a sized new operator for a library which broke older compiled expectations. 我需要sizeDealloc的代码,我的新编译器正在为一个库创建一个大小的新运算符,这打破了旧的编译期望。

As this is a compile flag, at least some of the code would be in your control, and you should be able to unravel the beast. 因为这是一个编译标志,所以至少有一些代码在你的控制之下,你应该能够解开这个野兽。

The constructor Stuff::Stuff is calling a function on an incompletely constructed object. 构造函数Stuff::Stuff在一个未完全构造的对象上调用一个函数。

That would create "Undefined behavior". 这将创建“未定义的行为”。 If the value "2" is not set till the end of the constructor (for example). 如果在构造函数结束之前未设置值“2”(例如)。

Probably the Singleton needs to be split into 2, one which delivers the early static data (eg 2). 可能需要将Singleton分成2个,一个提供早期静态数据(例如2)。

The second which delivers the held object Stuff. 第二个传递持有的物品Stuff。 Stuff would only rely on the first, which would break the deadlock. 东西只依靠第一个,这将打破僵局。

Alternatively, a second constructor to Stuff which told it which object to use, and was called from the Singleton::Singleton 或者, Stuff的第二个构造函数告诉它使用哪个对象,并从Singleton::Singleton调用

The MSDN article to disable "Magic Statics" MSDN : disable threadsafe static initialization MSDN文章禁用“Magic Statics” MSDN:禁用线程安全静态初始化

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM