C ++ Singleton被实例化两次 - 静态成员变量的问题
C++ Singleton gets instantiated twice - problem with static member variable
我已经像这样实现了标准单例模式(非线程版本):
hpp:
#ifndef SERVICEMANAGER_H
#define SERVICEMANAGER_H
#include <QObject>
#include <QVariant>
#include <QMap>
#include "IService.h"
#include "qhcore_global.h"
#include <QDebug>
class ServiceManager : public QObject
{
Q_OBJECT
public:
static ServiceManager* instance();
~ServiceManager(){qDebug()<<Q_FUNC_INFO;}
IService* service(QString name);
bool registerService(IService* service);
private:
explicit ServiceManager(QObject *parent = nullptr);
QMap<QString, IService*> _serviceMap;
static ServiceManager* __instance;
signals:
void serviceAdded(QString serviceName);
public slots:
};
#endif // SERVICEMANAGER_H
cpp:
ServiceManager* ServiceManager::__instance = nullptr;
ServiceManager::ServiceManager(QObject *parent) : QObject(parent)
{
qDebug()<<"CREATE::CTOR";
}
ServiceManager* ServiceManager::instance()
{
qDebug()<< __instance << "BEFORE";
if(__instance == nullptr)
{
qDebug()<<"CREATE";
__instance = new ServiceManager();
qDebug()<< __instance << "AFTER";
}
return __instance;
}
我的日志看起来像这样
[DEBUG 17.11. - 17:50:18:748] --
[DEBUG 17.11. - 17:50:18:748] -- QObject(0x0) BEFORE
[DEBUG 17.11. - 17:50:18:748] -- CREATE
[DEBUG 17.11. - 17:50:18:748] -- CREATE::CTOR
[DEBUG 17.11. - 17:50:18:748] -- ServiceManager(0x55e9fc6fb510) AFTER
[DEBUG 17.11. - 17:50:18:748] -- 0
[INFO 17.11. - 17:50:18:748] -- "Service registered: lab"
[DEBUG 17.11. - 17:50:18:748] -- 1
[INFO 17.11. - 17:50:18:749] -- "Added Resource factory for synclist for descriptor: labcontrol/logs"
[INFO 17.11. - 17:50:18:749] -- "Added Resource factory for synclist for descriptor: labcontrol/users"
[INFO 17.11. - 17:50:18:749] -- "Added Resource factory for synclist for descriptor: labcontrol/permissions"
[INFO 17.11. - 17:50:18:749] -- "Added Resource factory for synclist for descriptor: labcontrol/cards"
[INFO 17.11. - 17:50:43:973] -- "::ffff:192.168.1.32" has connected.
[INFO 17.11. - 17:50:43:985] -- "admin logged in. (" 1 sessions open)
[INFO 17.11. - 17:50:43:985] -- Device registered: "4f2o4o7b1a1r"
[INFO 17.11. - 17:50:44:003] -- Create ListResource with FS Resource Handler "logger/mappings_synclist"
[INFO 17.11. - 17:50:44:005] -- Create ListResource with FS Resource Handler "labcontrol/logs_synclist"
[INFO 17.11. - 17:50:44:007] -- Create ListResource with FS Resource Handler "labcontrol/users_synclist"
[INFO 17.11. - 17:50:44:009] -- Create ListResource with FS Resource Handler "labcontrol/permissions_synclist"
[INFO 17.11. - 17:50:44:011] -- Create ListResource with FS Resource Handler "labcontrol/cards_synclist"
[DEBUG 17.11. - 17:50:45:136] -- QObject(0x0) BEFORE
[DEBUG 17.11. - 17:50:45:136] -- CREATE
[DEBUG 17.11. - 17:50:45:136] -- CREATE::CTOR
[DEBUG 17.11. - 17:50:45:137] -- ServiceManager(0x55e9fc749340) AFTER
[DEBUG 17.11. - 17:50:45:137] -- COUNT: 0
[DEBUG 17.11. - 17:50:45:137] -- ()
[WARNING 17.11. - 17:50:45:138] -- "Unavailable servcie: lab"
在日志中可以看到单例会被实例化两次。我第二次调用 instance() 函数时,私有静态成员 __instance 再次持有一个 nullptr。这太奇怪了。相同的代码在不同平台的其他机器上运行完美 (OSx, Raspbian, ...)。
我的系统是 beelink BT3 pro 运行 Ubuntu 服务器 18.10,x64。代码本身是一个基于 WebSocket 的物联网云,它结合使用 Qt5 和插件。
我尝试了什么:
使用不同的编译器,例如 gcc-8、gcc-7 和 gcc-6。
自己编译Qt,确保所有二进制文件都是用同一个编译器构建的。
再说一次:我的应用程序使用了插件。这可能与以下事实有关:单例对象在不同的插件中使用,在运行时通过 QPluginLoader 从共享对象文件加载。
编辑:我不使用线程,也不使用不同的命名空间。
欢迎任何提示!提前致谢!
EDIT2 (解决方案):
(移至下面我的回答。)
如果您将您的 ServiceManager.cpp
(或 ServiceManager.o
)静态 link 到多个动态库,它们中的每一个最终都可能包含自己的 ServiceManager::__instance
实例。
解决方案是将 ServiceManager.o
放入一个单独的动态库中,供所有 "plugin" 库使用。
您应该使用宏 Q_GLOBAL_STATIC() 在插件之间共享实例。 cpp文件可以这样重写:
Q_GLOBAL_STATIC(ServiceManager, myServiceManagerInstance)
ServiceManager *ServiceManager::instance()
{
return myServiceManagerInstance();
}
不幸的是,之前的答案都没有用......还是同样的问题。
但是..我发现了问题:
在我的应用程序中有几个独立的插件和核心插件。最后一个是:插件和所有其他插件的共享库。
我的应用程序有一个相对搜索路径,它在其中查找要加载的插件。到目前为止,一切都很好。但是独立扩展插件需要在运行时找到link反对的核心插件。所以我复制核心插件到/usr/lib。这就是问题所在。 libCorePlugin.so 有两个副本 - 一个在插件文件夹中,另一个在 /usr/lib 中。我不知道为什么这在所有其他机器上都有效...但是让 LD_LIBRARY_PATH 指向公共插件文件夹而不是将文件复制到 /usr/lib 解决了问题。
有没有人知道为什么这在以前的某些系统上有效?
我已经像这样实现了标准单例模式(非线程版本):
hpp:
#ifndef SERVICEMANAGER_H
#define SERVICEMANAGER_H
#include <QObject>
#include <QVariant>
#include <QMap>
#include "IService.h"
#include "qhcore_global.h"
#include <QDebug>
class ServiceManager : public QObject
{
Q_OBJECT
public:
static ServiceManager* instance();
~ServiceManager(){qDebug()<<Q_FUNC_INFO;}
IService* service(QString name);
bool registerService(IService* service);
private:
explicit ServiceManager(QObject *parent = nullptr);
QMap<QString, IService*> _serviceMap;
static ServiceManager* __instance;
signals:
void serviceAdded(QString serviceName);
public slots:
};
#endif // SERVICEMANAGER_H
cpp:
ServiceManager* ServiceManager::__instance = nullptr;
ServiceManager::ServiceManager(QObject *parent) : QObject(parent)
{
qDebug()<<"CREATE::CTOR";
}
ServiceManager* ServiceManager::instance()
{
qDebug()<< __instance << "BEFORE";
if(__instance == nullptr)
{
qDebug()<<"CREATE";
__instance = new ServiceManager();
qDebug()<< __instance << "AFTER";
}
return __instance;
}
我的日志看起来像这样
[DEBUG 17.11. - 17:50:18:748] --
[DEBUG 17.11. - 17:50:18:748] -- QObject(0x0) BEFORE
[DEBUG 17.11. - 17:50:18:748] -- CREATE
[DEBUG 17.11. - 17:50:18:748] -- CREATE::CTOR
[DEBUG 17.11. - 17:50:18:748] -- ServiceManager(0x55e9fc6fb510) AFTER
[DEBUG 17.11. - 17:50:18:748] -- 0
[INFO 17.11. - 17:50:18:748] -- "Service registered: lab"
[DEBUG 17.11. - 17:50:18:748] -- 1
[INFO 17.11. - 17:50:18:749] -- "Added Resource factory for synclist for descriptor: labcontrol/logs"
[INFO 17.11. - 17:50:18:749] -- "Added Resource factory for synclist for descriptor: labcontrol/users"
[INFO 17.11. - 17:50:18:749] -- "Added Resource factory for synclist for descriptor: labcontrol/permissions"
[INFO 17.11. - 17:50:18:749] -- "Added Resource factory for synclist for descriptor: labcontrol/cards"
[INFO 17.11. - 17:50:43:973] -- "::ffff:192.168.1.32" has connected.
[INFO 17.11. - 17:50:43:985] -- "admin logged in. (" 1 sessions open)
[INFO 17.11. - 17:50:43:985] -- Device registered: "4f2o4o7b1a1r"
[INFO 17.11. - 17:50:44:003] -- Create ListResource with FS Resource Handler "logger/mappings_synclist"
[INFO 17.11. - 17:50:44:005] -- Create ListResource with FS Resource Handler "labcontrol/logs_synclist"
[INFO 17.11. - 17:50:44:007] -- Create ListResource with FS Resource Handler "labcontrol/users_synclist"
[INFO 17.11. - 17:50:44:009] -- Create ListResource with FS Resource Handler "labcontrol/permissions_synclist"
[INFO 17.11. - 17:50:44:011] -- Create ListResource with FS Resource Handler "labcontrol/cards_synclist"
[DEBUG 17.11. - 17:50:45:136] -- QObject(0x0) BEFORE
[DEBUG 17.11. - 17:50:45:136] -- CREATE
[DEBUG 17.11. - 17:50:45:136] -- CREATE::CTOR
[DEBUG 17.11. - 17:50:45:137] -- ServiceManager(0x55e9fc749340) AFTER
[DEBUG 17.11. - 17:50:45:137] -- COUNT: 0
[DEBUG 17.11. - 17:50:45:137] -- ()
[WARNING 17.11. - 17:50:45:138] -- "Unavailable servcie: lab"
在日志中可以看到单例会被实例化两次。我第二次调用 instance() 函数时,私有静态成员 __instance 再次持有一个 nullptr。这太奇怪了。相同的代码在不同平台的其他机器上运行完美 (OSx, Raspbian, ...)。
我的系统是 beelink BT3 pro 运行 Ubuntu 服务器 18.10,x64。代码本身是一个基于 WebSocket 的物联网云,它结合使用 Qt5 和插件。
我尝试了什么:
使用不同的编译器,例如 gcc-8、gcc-7 和 gcc-6。 自己编译Qt,确保所有二进制文件都是用同一个编译器构建的。
再说一次:我的应用程序使用了插件。这可能与以下事实有关:单例对象在不同的插件中使用,在运行时通过 QPluginLoader 从共享对象文件加载。
编辑:我不使用线程,也不使用不同的命名空间。
欢迎任何提示!提前致谢!
EDIT2 (解决方案):
(移至下面我的回答。)
如果您将您的 ServiceManager.cpp
(或 ServiceManager.o
)静态 link 到多个动态库,它们中的每一个最终都可能包含自己的 ServiceManager::__instance
实例。
解决方案是将 ServiceManager.o
放入一个单独的动态库中,供所有 "plugin" 库使用。
您应该使用宏 Q_GLOBAL_STATIC() 在插件之间共享实例。 cpp文件可以这样重写:
Q_GLOBAL_STATIC(ServiceManager, myServiceManagerInstance)
ServiceManager *ServiceManager::instance()
{
return myServiceManagerInstance();
}
不幸的是,之前的答案都没有用......还是同样的问题。 但是..我发现了问题:
在我的应用程序中有几个独立的插件和核心插件。最后一个是:插件和所有其他插件的共享库。 我的应用程序有一个相对搜索路径,它在其中查找要加载的插件。到目前为止,一切都很好。但是独立扩展插件需要在运行时找到link反对的核心插件。所以我复制核心插件到/usr/lib。这就是问题所在。 libCorePlugin.so 有两个副本 - 一个在插件文件夹中,另一个在 /usr/lib 中。我不知道为什么这在所有其他机器上都有效...但是让 LD_LIBRARY_PATH 指向公共插件文件夹而不是将文件复制到 /usr/lib 解决了问题。
有没有人知道为什么这在以前的某些系统上有效?