这是单例
#pragma once
class ContextManager {
public:
static ContextManager& Instance() {
static ContextManager instance;
return instance;
}
zmq::context_t& GetContext() { return ctx_;}
private:
zmq::context_t ctx_;
~ContextManager() {}
};
我有一个 DLL,其中包含一些有用的网络实用程序,它基于 ZeroMQ 构建,并使用此单例来不必传递上下文。
我将此 DLL 链接到运行测试套件的 EXE。该测试套件可以工作,发送和接收一些消息。当程序退出时,ContextManager 析构函数崩溃并显示“断言失败:成功的 WSASTARTUP 尚未执行(......\src\signaler .cpp:137)“
更多详情:
我不想向 DLL 客户端公开任何实现细节,因此我希望在 DLL 中包含此单例。如何才能实现这一目标?
问题是ZMQ使用的WinSock在使用前需要调用WSAStartup()。如果您随后调用 WSAShutdown() 并使用 ZMQ,则看起来好像从未调用过 WSAStartup(),因此断言失败。在更抽象的层面上,WSAStartup() 和 WSAShutdown() 之间的时间跨度必须完全包含 ZMQ 上下文的生命周期。
C++ 中的函数级静态是按需创建的,但在 main() 返回后被销毁(我相信以未指定的顺序)。您没有显示对 WSAStartup() 的调用,但我猜它位于 main() 内部的某个位置。类似地,对 WSAShutdown() 的调用是在 main 结束之前,但这仍然会将其置于函数静态对象的销毁之前,因此会出现您所看到的问题。
两个可能的修复:
您还可以为 DLL 创建两个类似于 WSAStartup() 和 WSAShutdown() 的函数,但这既不方便又丑陋。另外,除非绝对必要,否则我至少会考虑不使用单例。强迫用户对代码进行某种用途是很麻烦的,但这只是我个人的观点。
我现在在 Windows 7 上遇到同样的问题,这里有解决方案吗?