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 解决了问题。

有没有人知道为什么这在以前的某些系统上有效?