C++,Qt4 - QLabel.setText() 似乎会导致分段错误
Posted
技术标签:
【中文标题】C++,Qt4 - QLabel.setText() 似乎会导致分段错误【英文标题】:C++, Qt4 - QLabel.setText() seemingly causes segmentation fault 【发布时间】:2016-05-09 18:18:08 【问题描述】:编辑:问题已解决,请参阅我的回答。 TL;DR:与 Qt 无关,我在数组 (std::vector) 范围方面犯了一个愚蠢的错误。
使用 Windows7,Qt 版本 4.8.7,x86_64-w64-mingw32-g++ 作为编译器,Cygwin 用于编译,Notepad++ 用于编辑。 (同一个项目中也有 Flex 和 Bisonc++,但它们与问题无关并且工作正常。)
我有一个 std::vector,我尝试用数据填充它。在一个测试用例中(即 QFrame 包含从主函数获取数据的向量,不涉及其他类),这可以正常工作,正如预期的那样。 在另一种情况下,当使用 QMainWindow 触发它自己的调用相同函数的插槽方法时,它会在 QLabel.setText( QString::number() ) 部分遇到分段错误。
ui_parts.h
#ifndef UI_PARTS_H_INCLUDED
#define UI_PARTS_H_INCLUDED
#include <QWidget>
#include <QLabel>
#include <QGridLayout>
#include <QFrame>
#include <vector>
#include <string>
class regDisplay : public QFrame
Q_OBJECT
public:
regDisplay(int _meret, const std::string &nev, QWidget *parent = 0);
~regDisplay() ; // not actually in the header, here for compression
int size() const return meret; ;
void setValues(const std::vector<AP_UC> &val);
private:
QGridLayout* gridLayout;
int meret;
std::vector<unsigned char> valueVec;
std::vector<QLabel*> valueLabel;
;
#endif // UI_PARTS_H_INCLUDED
ui_parts.cpp
#include <iostream>
#include "ui_parts.h"
using namespace std;
regDisplay::regDisplay(int _meret, const std::string &nev, QWidget *parent)
: QFrame(parent), name(nev), meret(_meret)
valueVec.resize(meret, 0);
valueLabel.resize(meret, NULL);
gridLayout = new QGridLayout(this);
// [...] setting up other properties of the widget
for (int i = 0; i < meret; ++i)
valueLabel[i] = new QLabel(this);
// [...] set properties for valueLabel[i]
gridLayout -> addWidget( valueLabel[i], 1, i);
// the following function which is suspected with causing the segfault
void regDisplay::setValues(const std::vector<AP_UC> &val)
for (int i = 0; i < meret; ++i)
valueVec[i] = val[i];
cout << (int)valueVec[i] << "\t" << (QString::number( (int)valueVec[i] )).toStdString() << endl;
cout << "ptr: " << (valueLabel[i]) << endl;
if ( valueLabel[i] == NULL )
cout << "NULL POINTER? WTF " << i << endl;
else
cout << "not null pointer " << i << endl;
cout << "kek" << endl;
valueLabel[i] -> setText( QString::number( (int)valueVec[i] )); // SEGFAULT
cout << i << "+" << endl;
调用函数:
vector<unsigned char> vecUC(4);
allapot.get_reg("eax", vecUC); // I'm 100% sure this works correctly, tested thoroughly
// it makes vecUC equal to an std::vector<unsigned char> which is 4 long
eax -> setValues( vecUC ); // regDisplay* eax;
// initialized: eax = new regDisplay(4, "eax", this ); in the constructor of this class (which inherits from QMainWindow)
这段代码的控制台输出:
0 0
ptr: 0x32f160
not null pointer 0
kek
Segmentation fault
我对此的阅读: valueVec[i] 及其 QString 版本均为 0(setText() 的参数似乎没问题) valueLabel[i] 有一个不为 0 的指针值,在构造函数中这样初始化 valueLabel[i] 不是空指针(在这种情况下 i == 0) setText() 工作之前的第一个 cout,第二个没有
从整个代码中删除(注释)setText() 调用使其正常工作(但我需要某种方式在 UI 上显示文本,因此出于程序的目的需要它们以某种形式)。 'make ui_vec' 为 regDisplay 和 veremDisplay 类创建测试模块,效果很好 'make ui_main' 为 mainDisplay 创建了测试模块,这会导致问题出现
我不知道是什么导致了这个问题,如果能帮助我解决这个问题,我将不胜感激。提前谢谢你。
更新 (16.05.14): 我在 wxWidgets 中重新创建了整个项目,它的工作原理非常相似,但基本上在同一点上,它也开始抛出段错误。它似乎是随机发生的,有时整个程序都能正常运行,有时在第一个操作时就失败了。
但是,通过gdb运行程序完全解决了这个问题,我没有遇到任何段错误。
更新 (16.05.16): 经过一些进一步的测试,问题似乎出在我创建的 bisonc++ / flex 解析器的某个地方。有一段使用它的代码每次都可以正常工作,如果我尝试添加它(使用 std::stack 返回到以前的状态;使用类进行导航),它会在第二条指令之后出现段错误(首先工作正常)。
脚注:
Link for repository - 问题出在 src/cpp/ui_parts.cpp line79 (regDisplay::setValues()),从 mainDisplay::displayAllapot() (src/cpp/ui_main.cpp line195) 调用。调试消息可能有所改变,其余代码相同。 大多数文档和评论都是匈牙利语而不是英语,对此我深表歉意。
另一个(可能相关的问题):同一程序有时会在不同位置遇到相同的分段错误 - 有时 regDisplay::setValues() 工作正常,问题出现在 veremDisplay::updateValues() - 在循环,可能在第一次运行时,也可能在以后运行,有时它会在整个过程中运行,我还没有看到它有任何一致性(它在第一次运行时大多停止运行)。
第三个问题(同样,很可能是相关的):当调用 openFile() 函数时,它会正常运行直到结束(最后一条指令是调试消息并且工作正常),但会出现 seg-fault(这会使我想到了析构函数问题)。但是,如果我将不同的函数 (oF2()) 连接到同一个事件,然后让 oF2() 调用 openFile() 并编写调试消息(仅此而已),则显示调试消息并出现分段错误之后 - 并且没有接收到局部变量或参数,因此在代码的最后一条指令和函数终止之间不应运行析构函数。
【问题讨论】:
您需要发布调整该向量大小的代码和/或 QLabel 指针的填充方式。此外,当您对向量进行循环时,检查实际向量大小是有意义的。当然,您使用的确切版本的这些细节似乎都不重要。关于存储库:不,最好在此处提供足够的示例。有一个完整的最低要求示例的常见问题解答。请查找并阅读。 ***.com/help/mcve @AlexanderVX 我根据要求添加了一些额外的代码,但问题的主要问题是它在某些情况下有效(即单元测试)而在其他情况下失败(即使用应该的模块进行测试)用它)。我的主要目的是了解是否有任何“新手”错误可能导致这种情况,或者了解导致不一致的原因。明天我会尝试重写,看看我可以发布哪些代码更有意义(整个代码库超过 3k 行,这是建立在迄今为止所做的一切之上的最后一部分,因此很难拼凑出相关的内容)。 在 setValues 中我看不到你从哪里得到变量 'meret'。 旁注:如果您在std::string
和QString
之间遍历,99% 的情况下您不应该这样做。
【参考方案1】:
我发现了这个问题,我在一个只有 7 大小的 std::vector 中增加了 10 个(它只出现在某些测试用例中),修复了我遇到的所有问题,到目前为止没有出现分段错误相当广泛的测试。
由于真正的问题与 Qt 没有任何关系(也与 bisonc++ 或 flex 无关),除了“检查您的数组范围”课程之外,我认为没有任何真正的理由保留这个线程大约。如果模组看到这一点,请随时删除问题 - 如果解决方案不足以保持它。
【讨论】:
【参考方案2】:我在您的代码中没有看到可能导致段错误的问题。
但我猜你的编译标志可能会导致这样的段错误。
例如,您使用std::string
和toStdString
。
如果Qt
使用其他版本的编译器编译,或者例如,如果您使用c++ runtime library
(根据您的makefile[-static-libgcc -static-libstdc++] 和Qt
进行静态链接)和Qt
与c++ runtime
的dll 变体链接,那么您的程序和Qt
库可能认为它们与std::string
的相同版本一起工作,但实际上与std::string
的不同版本一起工作,
和std::string
内部分配的Qt
可能会导致段错误,当您调用
它在你的程序中的析构函数。或者您使用由fopen
创建的FILE *
创建QFile
,并在~QFile
中捕获段错误,因为Qt
FILE
和您的FILE
不同。
因此,请确保您的 Qt
使用与您的程序相同的编译器进行编译,
并且Qt
使用与您的程序相同的标志进行构建。
其实sizeof(std::string)
和sizeof(FILE)
可能是一样的,但是可以使用不同的分配器。
【讨论】:
删除与 C++ 运行时库的静态链接并没有解决问题。我没有编译 Qt 库,我使用的是 Cygwin 安装程序给我的库(我假设是预编译的)。我使用的编译器 (x86_64-w64-mingw32-g++) 与 qmake 放入它生成的 makefile 中的编译器相同,与用于编译的标志相同。 @Nightelfpala 我不是cygwin
的专家,但cygwin
编译器和mingw
是不同的东西,所以如果你从cygwin
得到Qt
,那么你应该gcc
和g++
是 cygwin 自带的,而不是 x86_64-w64-mingw32-g++
与g++
链接会导致许多未定义的引用。基本上我所做的:使用 cygwin 包安装程序获取 Qt(以及 qmake 和 x86_64-w64-mingw32-g++ 等依赖项),然后使用 qmake
生成一个 makefile,复制其中的一部分直到它编译。生成的 makefile 将上述 mingw 命名为其编译器 - 基于那些(尤其是生成的包含/库路径),在我看来,这个特定版本的 Qt 仅与 mingw 兼容。以上是关于C++,Qt4 - QLabel.setText() 似乎会导致分段错误的主要内容,如果未能解决你的问题,请参考以下文章
Qt4 C++ Pointer to const QList of pointers
C++ 和 QT4.5 - 传递 const int& 过大?通过引用传递是不是有助于信号/插槽?
在symbian3里怎么安装Qt 我现在装了Symbian3的sdk,qt4.7.1也安装了。但是在carbide c++里,选择qt编译报