单例线程安全程序

时间:2015-02-15 08:32:00

标签: c++ qt singleton static-members

我试图在Qt中用单例设计编写一个简单的应用程序。以下是头文件:

#ifndef MAINWINDOW_H

#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    static MainWindow *getInstance();
    ~MainWindow();

private:
    explicit MainWindow(QWidget *parent = 0);
    static MainWindow *uniqueInstance;
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

这是实施文件:

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow* MainWindow::uniqueInstance = new MainWindow();


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

MainWindow* MainWindow::getInstance()
{
    return uniqueInstance;
}

最后这里是主要功能:

#include <QApplication>
#include "mainwindow.h"

#include "QThread"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    MainWindow *w = MainWindow::getInstance();
    w->show();

    return a.exec();
}

我的程序的构建是可以的。但是我收到了运行时错误&#34; QWidget:必须在QWidget&#34;之前构造一个QApplication。我该怎么做才能解决这个问题?我想使用这种形式的单例来创建一个线程安全的程序。

提前感谢您的帮助。

3 个答案:

答案 0 :(得分:1)

安全地保存全局对象实例的Qt-idiomatic方法是Q_GLOBAL_STATIC。该实例是在第一次使用时创建的。这样,在QApplication实例存在后,将在需要时创建您的单例实例。

而不是MainWindow* MainWindow::uniqueInstance = new MainWindow(),你写的是:

Q_GLOBAL_STATIC(MainWindow, uniqueInstance);

答案 1 :(得分:1)

根据之前的答案以及http://doc.qt.io/qt-5/qglobalstatic.html#Q_GLOBAL_STATIC,答案如下:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT
    friend class myClass;

public:
    static MainWindow *getInstance();
    ~MainWindow();

private:

    explicit MainWindow(QWidget *parent = 0);
    Ui::MainWindow *ui;
};

class myClass : public MainWindow
{
};

#endif // MAINWINDOW_H

.cpp文件如下所示:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QGlobalStatic>

Q_GLOBAL_STATIC(myClass,uniqueInstance)

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

MainWindow* MainWindow::getInstance()
{
    return uniqueInstance;
}

最后主文件如下:

#include <QApplication>
#include "mainwindow.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    MainWindow *w = MainWindow::getInstance();
    w->show();

    return a.exec();
}

这是有效的并且是线程安全的。

答案 2 :(得分:-1)

MainWindow* MainWindow::uniqueInstance = new MainWindow();

这是全局实例,它发生在main函数之前,所以这个构造函数早于main函数,这是不允许的。 Qt需要首先构建QApplication,然后构建小部件。所以你需要在构造函数之后将它移动到main中的QApplication,或者只是删除它。

MainWindow* MainWindow::uniqueInstance = 0;

然后在QApplication之后构造该对象。

正如我所说,你不应该在main之前构造uniqueInstance,修改一些基于你的POST的代码,它应该可行。

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow* MainWindow::uniqueInstance = 0;


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

MainWindow* MainWindow::getInstance()
{
    if (0 == MainWindow::uniqueInstance){
        MainWindow::uniqueInstance = new MainWindow();
    }
    return MainWindow::uniqueInstance;
}

基于Kuba的POST,引入了一个新的全局MACRO用于创建这种SINGLETON(Q_GLOBAL_STATIC http://qt-project.org/forums/viewthread/13977),它更优雅,但是,这个宏只存在于Qt5,而不是Qt4,并且还有您应注意的一些使用限制。基本上它也是一个用于包装代码以在运行时创建单例的宏。