【问题标题】:Global and Local variable, running into problem with connect()全局和局部变量,connect() 遇到问题
【发布时间】:2021-03-15 15:36:03
【问题描述】:

我有这个代码: mainclass.cpp 文件:

#include "mainclass.h"
#include <QtDebug>
#include <QApplication>

Domino *domino = new Domino();

int main(int argc, char *argv[])
{
    qDebug()<< __FUNCTION__;
    QApplication a(argc, argv);
    MainClass w;
    w.show();
    return a.exec();
}

MainClass::MainClass(QWidget *parent) : QMainWindow(parent)
{
    qDebug()<< __FUNCTION__;
    //Domino *domino = new Domino();
    connect(domino, SIGNAL(OneImageReceivedSignal()), this, SLOT(OneImageReceivedSlot()));
    domino->ReceiveAnImage();
}

void MainClass::OneImageReceivedSlot(){
    qDebug()<< __FUNCTION__;
}

domino.cpp 文件:

#include "domino.h"
#include <QtDebug>
Domino::Domino(QObject *parent) : QObject(parent)
{
    qDebug()<< __FUNCTION__;
    cdl_img_acquisition_= new CDLImageAcquisition();
    connect(cdl_img_acquisition_, SIGNAL(OneImageReceivedSignal()), this, SIGNAL(OneImageReceivedSignal()));
}


void Domino::ReceiveAnImage(){
    qDebug()<<__FUNCTION__;
    cdl_img_acquisition_->ReceiveAnImage();
}


CDLImageAcquisition *Domino::get_cdl_img_acquisition(){
    qDebug()<< __FUNCTION__;
    return this->cdl_img_acquisition_;
}

icdlimageacquisition.cpp 文件:

#include "cdlimageacquisition.h"
#include<QtDebug>

CDLImageAcquisition::CDLImageAcquisition(QObject *parent) : QObject(parent)
{
    qDebug()<< __FUNCTION__;
    icdlcam_=new ICDLCam();
    connect(icdlcam_, SIGNAL(OneImageReceivedSignal()),this, SIGNAL(OneImageReceivedSignal()));
}

void CDLImageAcquisition::ReceiveAnImage(){
    qDebug()<<__FUNCTION__;
    icdlcam_->ReceiveAnImage();
}

ICDLCam *CDLImageAcquisition::get_cdl_cam(){
    qDebug()<< __FUNCTION__;
    return this->icdlcam_;
}

icdlcam.cpp 文件:

#include "icdlcam.h"
#include <assert.h>
#include <QtDebug>

ICDLCam::ICDLCam(QObject *parent) : QObject(parent)
{
    qDebug()<< __FUNCTION__;
}


void ICDLCam::ReceiveAnImage(){
    qDebug()<<__FUNCTION__;
    emit OneImageReceivedSignal();
}

当我使用 MSVC 2015 或 2019 构建和运行时,程序崩溃如下:

15:57:25: Starting C:\Users\User\source\DL01-SOFTWARE\build-DOMINO-TEST2-Desktop_Qt_5_15_0_MSVC2019_64bit-Debug\Lib\debug\Lib.exe ...
Domino::Domino
CDLImageAcquisition::CDLImageAcquisition
ICDLCam::ICDLCam
15:57:27: The program has unexpectedly finished.
15:57:27: The process was ended forcefully.
15:57:27: C:\Users\User\source\DL01-SOFTWARE\build-DOMINO-TEST2-Desktop_Qt_5_15_0_MSVC2019_64bit-Debug\Lib\debug\Lib.exe crashed.

调试器在 CDLImageAcquisition 构造函数的connect(icdlcam_, SIGNAL(OneImageReceivedSignal()),this, SIGNAL(OneImageReceivedSignal())); 处崩溃。

它显示此消息对话框:“异常触发:下级停止,因为它触发了异常。在线程 0 中停止:异常在 0x7fff9dd8da2a,代码:0xc0000005:读取访问冲突:0x0,标志 = 0x0(第一次机会) .

程序在以下情况下不会崩溃:

  • 我在 MainClassconstructor 的局部范围内声明并初始化 domino 变量
  • 无论dominovariable 的范围如何,我都使用 MinGW 编译器构建和运行。

我必须在不支持 MinGW 编译器的 Windows 中使用 Pylon API,并且稍后我还需要domino 变量的全局范围。我也试过把它作为一个类的静态成员,但结果是一样的。

【问题讨论】:

  • 你不想打电话给a.exec()?见tutorial。很可能您只是过早退出。此外,请考虑使用智能指针 (std::unique_ptr&lt;Domino&gt;)。
  • 谢谢,我刚刚编辑了 main() 函数。因为我在发问题之前试图清理代码,所以被删除了,错误是一样的。
  • 我试过 std::unique_ptr domino(new Domino());然后连接(domino.get(),信号(OneImageReceivedSignal()),这个,SLOT(OneImageReceivedSlot()));它给出了同样的错误。
  • 将 Domino 变量设为静态是否有帮助? static Domino *domino = new Domino();.
  • @E4z9 正如我在帖子中提到的,我尝试了static,但结果与全局相同,因为我必须在函数的本地范围之外对其进行初始化。

标签: c++ qt visual-c++ global-variables


【解决方案1】:

我没有解释究竟会发生什么,我只能假设 Win32 API 在这里发生了一些 Qt 魔法。

对于GUI(非控制台)应用程序,起点不是main,而是WinMain,这就是为什么Qt将main重新定义为qMainhttps://code.qt.io/cgit/qt/qtbase.git/tree/src/gui/kernel/qwindowdefs.h?h=5.15#n114)并链接到一个特殊的qtmain静态图书馆(https://code.qt.io/cgit/qt/qtbase.git/tree/src/winmain/?h=5.15),其中的细节让我难以理解......

无论如何,重现该问题的最小示例:

main.cpp:

#include <QObject>

class Test : public QObject
{
    Q_OBJECT
public:
    Test() {
        connect(this, &Test::sig, this, &Test::slot);
    }

    void slot() {}
signals:
    void sig();
};

Test *t = new Test;

int main(int argc, char *argv[]) {
//    Test t;
     return 0;
}

#include "main.moc"

test.pro

CONFIG += c++11
SOURCES += main.cpp

上述崩溃。

如果您在 main 中而不是全局创建 Test 对象,则它不再崩溃。

如果您将其构建为控制台应用程序,它将不再崩溃,即在将 CONFIG 行更改为 CONFIG += c++11 console、重新运行 qmake 和重建时。

底线:你不能在main之前使用connect

除了不在全局对象的构造函数中调用connect(或不使用全局对象)之外,您还有其他选项:

在main中分配全局对象

Test *t = nullptr;

int main(int argc, char *argv[]) {
    t = new Test;
    return 0;
}

使用 Q_GLOBAL_STATIC

Q_GLOBAL_STATIC 创建的对象在第一次使用时会自行初始化,这意味着它不会增加应用程序或库的加载时间。此外,该对象在所有平台上都以线程安全的方式初始化。

Q_GLOBAL_STATIC(Test, t)

通过t-&gt;someMethod() 调用方法或使用t() 访问指针,在其他地方访问对象,例如connect(t(), &amp;Test::sig, .....).

【讨论】:

  • 非常感谢。这解决了我的问题。除了回答为什么它适用于 MINGW 编译器而不适用于 MSVC 编译器之外,我再次调试并注意到在 main() 之前使用全局初始化时(例如 Test t = new Test)。 MSVC 从动态初始化开始。因此,在main() 之前,在调用connect() 函数时,Test 对象为空。应用程序此时崩溃。 MINGW开始静态初始化,connect()没有问题。
  • 如果您喜欢这个答案并认为它可以解决您的问题,请考虑“接受”它。
猜你喜欢
  • 2022-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-08
  • 1970-01-01
  • 2023-03-14
  • 1970-01-01
  • 2019-07-28
相关资源
最近更新 更多