单例线程安全程序

Singleton thread-safe programs

我正在尝试用 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();
}

我的程序构建正常。但是我收到 运行 次错误 "QWidget: Must construct a QApplication before a QWidget"。我应该怎么做才能解决这个问题?我想用这种形式的单例来做一个线程安全的程序。

在此先感谢您的帮助。

礼萨

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

这是全局实例,发生在main函数之前,所以这个构造函数早于main函数,这是不允许的。 Qt 需要先构建QApplication,然后再构建widget。所以你需要在 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的基础上,引入了一个新的全局宏来创建这种SINGLETON(Q_GLOBAL_STATIC http://qt-project.org/forums/viewthread/13977),更优雅,但是,这个宏只是存在于 Qt5,而不是 Qt4,并且还有一些您应该注意的使用限制。基本上它也是一个宏,用于包装代码以在运行时创建单例。

线程安全地持有全局对象实例的 Qt 惯用方法是通过 Q_GLOBAL_STATIC。该实例是在第一次使用时创建的。这样,您的单例实例将在需要时创建,在 QApplication 个实例存在之后。

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

Q_GLOBAL_STATIC(MainWindow, uniqueInstance);

根据之前的回答以及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();
}

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