【问题标题】:Segfault when accessing QApplication::arguments访问 QApplication::arguments 时的段错误
【发布时间】:2016-06-04 15:15:49
【问题描述】:

在为 gui 编写包含qt 的程序时,我偶然发现了一个问题,可以用下面的最少代码重现:

#include <iostream>
#include <QApplication>
#include <QSettings>

using namespace std;

int main(int argc, char ** argv) {
    QApplication *app;
    {
        int tmp_argc = argc;
        app = new QApplication(tmp_argc, argv);
    }
    QSettings settings("testvendor");
    cout<<"Num of arguments: "<<app->arguments().count()<<std::endl;
    return 0;
}

运行会导致核心转储(在对 QApplication::arguments 的调用中)或 Num of arguments: 0,这显然是错误的。

如果我用app = new QApplication(argc, argv) 实例化app(使用带有参数计数的无作用域变量)或删除settings 的声明/定义 - 程序按预期输出Num of arguments: 1(其中任何一项更改就足够了)。

我在Ubuntu上使用Qt 5.5,项目是基于cmake的,CMakeLists.txt的内容:

cmake_minimum_required(VERSION 3.3)
project(qtest)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

set(CMAKE_PREFIX_PATH /opt/Qt/6.5.1/gcc_64/)
find_package(Qt5Widgets REQUIRED)

set(SOURCE_FILES main.cpp)
add_executable(qtest ${SOURCE_FILES})
target_link_libraries(qtest Qt5::Widgets)

【问题讨论】:

    标签: c++ qt qt5 qt5.5


    【解决方案1】:

    警告:argc 和 argv 必须在 QApplication 对象的整个生命周期内保持有效。此外,argc 必须大于零,并且 argv 必须至少包含一个有效字符串。"

    From QT 5 Documentation。强调我的。

    tmp_argc 超出范围。

    QApplication *app;
    {
        int tmp_argc = argc;
        app = new QApplication(tmp_argc, argv);
    } <-- BOOM!
    

    【讨论】:

    • 该死,我从没想过他们会要求我保留一些 int 变量,这太疯狂了!看到 qapplication 是如何以某种方法实际创建的,我想我也必须通过引用传递它。
    • 大声笑。来自地狱的设计师再次骑行。让我们以 int 作为参考并崩溃,然后编写有关它的文档!参考(指针)可能大于 int 值,但是嘿 - 向那些是老板的人展示并告诉他们:“RTFM”会很有趣。
    • 我可以看到调用者需要知道 QApp 对 args 列表做了什么的用例,所以我得到了参考。我可以看到存储引用的唯一原因是,如果您想让 QApp 和包含程序在程序过程中操纵 args 列表,而不是预先加载参数集合。
    • @Cthulhu “允许 QApp 和包含程序来操作 args 列表”这正是QApplication 所做的准确。请记住,Qt 有自己的命令行选项——在您的代码看到如此修改的参数列表之前,它们将被解析和删除。没有什么疯狂的。
    【解决方案2】:

    按照QCoreApplication构造函数文档中给出的要求,这是修复它的方法:

    // https://github.com/KubaO/stackoverflown/tree/master/questions/app-args-35566459
    #include <QtCore>
    #include <memory>
    
    std::unique_ptr<QCoreApplication> newApp(int & argc, char ** argv) {
       return std::unique_ptr<QCoreApplication>(new QCoreApplication{argc, argv});
    }
    
    int main(int argc, char ** argv) {
        std::unique_ptr<QCoreApplication> app(newApp(argc, argv));
        QSettings settings{"testvendor"};
        qDebug() << "Num of arguments: " << app->arguments().count();
    }
    

    【讨论】:

    • 是的,所以基本上我也通过引用将 argc 和 argv 传递到工厂方法中。
    猜你喜欢
    • 2013-01-19
    • 1970-01-01
    • 2015-04-20
    • 1970-01-01
    • 1970-01-01
    • 2014-04-10
    • 1970-01-01
    • 2015-02-22
    • 2016-09-27
    相关资源
    最近更新 更多