C ++ Singleton实例化两次-静态成员变量问题

时间:2018-11-19 10:22:07

标签: c++ qt plugins singleton

我已经实现了标准的单例模式(非线程版本),如下所示:

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等)的其他计算机上完美运行。

我的系统是运行Ubuntu Server 18.10 x64的beelink BT3 pro。代码本身是基于WebSocket的IoT Cloud,结合使用Qt5和插件。

我尝试过的事情:

使用不同的编译器,例如gcc-8,gcc-7和gcc-6。 我自己编译Qt,以确保所有二进制文件都使用相同的编译器构建。

再次:“我的应用”使用插件。可能与单例对象用于不同的插件中有关,该插件在运行时通过QPluginLoader从共享对象文件中加载。

edit:我不使用线程,也不使用其他名称空间。

欢迎任何提示!预先感谢!

EDIT2 (解决方案)

(移至下面的答案。)

3 个答案:

答案 0 :(得分:2)

您应该使用宏Q_GLOBAL_STATIC()在插件之间共享实例。可以这样重写cpp文件:

const data = [
  {"PermCode":"BOF","IsvalidPerm":true},
  {"PermCode":"CM","IsvalidPerm":false},
  {"PermCode":"CV","IsvalidPerm":true},
  {"PermCode":"DAS","IsvalidPerm":true},
  {"PermCode":"RPT","IsvalidPerm":true},
  {"PermCode":"VM","IsvalidPerm":true}
];

const formatted = data.reduce((acc, curr) => ({ ...acc, [curr.PermCode]: curr.IsvalidPerm }), {});

console.log(formatted);

答案 1 :(得分:1)

如果您将ServiceManager.cpp(或ServiceManager.o)静态链接到多个动态库,则每个动态库最终都可能包含其自己的ServiceManager::__instance实例。

解决方案是将ServiceManager.o放入一个单独的动态库,该库可供您所有“插件”库使用。

答案 2 :(得分:0)

不幸的是,之前的答案没有奏效……仍然是同样的问题。 但..我发现了问题:

在我的应用程序中有几个独立的插件和核心插件。最后一个是两者:一个插件和所有其他插件的共享库。 我的应用程序有一个相对的搜索路径,用于查找要加载的插件。到目前为止,一切都很好。但是独立的扩展插件需要在运行时找到要链接的核心插件。因此,我核心插件复制到了/ usr / lib。这就是问题所在。 libCorePlugin.so有两个副本-一个在plugin文件夹中,另一个在/ usr / lib中。我不知道为什么这在所有其他机器上都起作用...但是让LD_LIBRARY_PATH指向公共插件文件夹,而不是将文件复制到/ usr / lib即可解决此问题。

有人知道为什么以前在某些系统上可以使用吗?