【问题标题】:QPlainTextEdit throwing std::bad_allocQPlainTextEdit 抛出 std::bad_alloc
【发布时间】:2012-08-08 15:37:51
【问题描述】:

我有一个程序可以运行适合某些数据的最小二乘法。此过程在单独的线程中运行,并通过对话框进行控制。这个对话框有一个 QPlainTextEdit 显示拟合更新和最终报告。

对话框是在 Qt Designer 中创建的,代码在 QtCreator 中运行,我的 Qt 版本是 4.8.1。

我遇到的问题有点不稳定。当我第一次运行该程序时,一切都很好。然后如果我再次运行它,有时程序会崩溃并显示消息

在抛出 'std::bad_alloc' 的实例后调用终止 什么():std::bad_alloc 程序意外结束。

我跟踪到调用 QPlainTextEdit 的 clear() 方法的问题。这是一些代码。

// Snippets of the class definition
class QLSQDialog : public QDialog, public Ui_QLSQDialog
{
  Q_OBJECT
public:
  QLSQDialog(QWidget *parent = 0);
  (...)
  void UpdateDisplay(const QString &msg, int iter, double norm);  // Update values of chi, etc on displays
signals:
  void Run();           // Signal to run a LSQ procedure
  (...)
private slots:
  void on_btnRun_clicked();
  (...)
private:
  void Enables(bool running);   // Enable and disable features depending on running state of LSQ fit
  (...)
};


// Snippets of the class implementation

QLSQDialog::QLSQDialog(QWidget *parent) : QDialog(parent)
{
  setupUi(this);          // Set up dialog
  (...)
  txtInfo->clear();  // txtInfo is a QPlainTextEdit created in Designer
  (...)
}

void QLSQDialog::UpdateDisplay(const QString &msg, int iter, double norm)
{
  lblChi->setText(QString::number(norm,'f',12));
  if (iter >= 0) lblIt->setText(QString::number(iter));
  txtInfo->appendPlainText(msg);
}

void QLSQDialog::on_btnRun_clicked()
{
  txtInfo->clear();   // Offending line in second run
  Enables(true);
  emit Run();
}

void QLSQDialog::Enables(bool running)
{
  bool Idle = !running;
  bool HasReport = !txtInfo->document()->isEmpty();
  (...)
  btnReport->setEnabled(Idle && HasReport);
}

txtInfo 是 QPlainTextEdit 对象。当对象是 创建以显示空文本编辑。当我单击“运行”工具按钮时,其默认插槽会发出一个运行信号,该信号将启动新线程。 txtInfo QPlainTextEdit 在这个线程中更新,直到它完成(实际上,线程发出一个信号,该信号被主应用程序捕获,然后调用UpdateDisplay)。

如果我再次单击运行按钮,则会出现崩溃和错误。如果我将txtInfo->clear()txtInfo->document()->clear()txtInfo->setPlainText("")txtInfo->document()->setPlainText("") 替换为相同的问题(第二次执行时崩溃)。偶尔,但不经常,我可以在崩溃之前运行几次(大约 10 次)。

最后,如果我注释掉 txtInfo->clear() 行,那么我可以尽我所能运行例程(在一个测试中,我在运行它大约 80 次后感到疲倦)。

我唯一的(几乎是随机的)猜测是问题与线程的更新有关(它发出一个被捕获的信号,然后调用UpdateDisplay 函数)。我这么认为的原因是,如果我注释掉信号并创建一个新按钮来调用带有一些虚假信息的UpdateDisplay,一切都很好。

违规行前的qApp->processEvents() 无效。

我被困在这里。欢迎任何想法。例如,我可以做任何测试来验证调用clear() 方法是否正常?

【问题讨论】:

  • 您可能不应该从线程调用QWidget 方法。它们不是线程安全的。您需要为您的主 gui 线程发出信号以查看,并通过调用方法直接响应。
  • 确实,你是对的,我确实为此遇到了麻烦。我的描述有点短。我有一个在线程中运行的工作对象。它发出一个带有更新参数的信号。该信号被主应用程序捕获,然后调用 UpdateDisplay。我已经编辑了问题以指出这一点。

标签: c++ qt qtextdocument qplaintextedit


【解决方案1】:

我最终将这个问题归结为我的代码中严重的内存泄漏。我“修复”了代码,但我仍然对为什么会发生问题感到有些困惑。

基本上,我在某处创建了一个大的vector<double> 并将其地址传递给调用vector<double> * 变量的函数。问题是在函数完成使用之前原始向量不再存在。经典的愚蠢错误。可能QPlainTextEdit 文档在vector<double> 曾经所在的区域分配空间:预期的不稳定行为。但我没想到会崩溃。

向量是“只读的”。使用它的函数只读取值并将计算存储在其他地方。现在让我们假设纯文本在先前由vector<double> 寻址的内存中创建了一些东西。在这种情况下,当我QPlainTextEdit::clear() 纯文本文档时,向量先前指向的值会发生变化,我希望计算是没有意义的。当函数访问现在已故的指向vector<double> 的指针时,我也会接受崩溃。但是我不希望程序在我清除文本时崩溃,毕竟这是一个有效的指针。

无论如何,如果有人知道,我很想知道为什么会发生崩溃。但除此之外,一旦泄漏被修复,问题就消失了。当然,知道原因绝对不是不修复泄漏的借口。

【讨论】:

  • 在调用该向量时附上一些关于其大小的断言,以确保它不会为空。
  • 这是个好建议。但仍然让我感到困惑的是,崩溃不是来自访问已故向量,而是来自新生的文本编辑。
  • 这个QPlainTextEdit充满了内存泄漏,不要使用它
猜你喜欢
  • 1970-01-01
  • 2012-08-24
  • 2016-04-04
  • 1970-01-01
  • 2012-01-16
  • 2011-05-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多