【问题标题】:Qt throws error when allocating too much dynamic memory within a classQt 在类中分配过多动态内存时抛出错误
【发布时间】:2012-07-11 06:54:46
【问题描述】:

我有一个分配一些内存的类。例如:

class image {

public:
    image(){
        pixelvalue = 0;
    }

    void formatandcopy() {
        pixelvalue = new int [10000*50000];
        if(pixelvalue)
            qDebug()<<"allocation successful"; 
        else 
            qDebug()<<"allocation failed";
    }
private:
    int *pixelvalue;
};

当我调用formatandcopy() 时,程序会抛出这个:

Qt has caught an exception thrown from an event handler. Throwing
exceptions from an event handler is not supported in Qt. You must
reimplement QApplication::notify() and catch all exceptions there.

有人知道我可以如何防止这种情况并让用户知道它只是内存不足吗?当我运行它时,它甚至不显示allocation failed。在调用qDebug() 之前会抛出上述错误。如果分配的内存量减少,程序运行良好。我认为这很奇怪,因为在使用 new 运算符而不是 qt 函数时会引发此错误。此外,我的机器还有足够的内存。我认为这是 qt 将其程序限制在某个堆空间的结果。最后,如果我可以通过重新实现 notify 函数来解决这个问题,那么任何人都可以指出我正确的方向吗?

【问题讨论】:

  • 我猜你可以重新实现 QApplication::notify() 并在那里捕获异常......只是你理解的猜测......
  • 这里的解决方法是弄清楚为什么你的程序试图分配过多的内存并阻止它开始。我不希望看到一个消息框告诉我程序内存不足而没有一个可行的解决方案。
  • 是的,这是真的。现在正在发生错误,因为我正在加载一个“解压缩”它并将每个像素值存储在数组中的 jpg。我需要像素值来进行一些图像处理。截至目前,我预计不需要非常大的图像(如 10,000x10,000 像素),但如果有人决定加载这样的大图像,我想实施安全防护。将来我会考虑实现分解图像或将图像插入到更小的尺寸的功能。

标签: c++ qt memory-management new-operator


【解决方案1】:

您应该能够捕获 std::bad_alloc 以处理该函数中的异常。例外是标准 C++ 的一部分。

try {
  // ...
} catch (std::bad_alloc &a) {
  // ...
}

如果它超出该范围(进入 Qt 事件处理),那么您将必须按照他们指定的方式实现 QApplication::notify

作为警告,错误的分配通常是不可恢复的。例外情况是,当您知道自己分配了非常大的内存量(可能基于用户输入),而您通常不会使用非常消耗内存的应用程序。

编辑:

澄清一下,如果您的应用程序设计允许您耗尽内存,那么如果您捕获 bad_allocs 并忽略它们,则不太可能发生任何变化。该程序已死,您将只能显示有关所发生情况的错误消息。这也很棘手,因为您不能分配任何内存来创建消息框!

反例是向用户询问文件并将其全部读入内存的场景。最终他们会尝试给你一个他们没有内存的文件,你可以安全地告诉他们尝试另一个文件。这类问题通常在应用程序中是孤立的,非常值得警惕。

【讨论】:

  • Tom,似乎所有动态内存分配都应该在 try-catch 块中。拥有一个接收指针并在try-catch 块内为其分配内存的函数会有任何缺点吗?
  • @user1346994 try/catch 块也会产生 一些 开销,但通常您不必担心这一点。它使代码更难阅读,特别是考虑到除了忽略它之外,您将无法对 bad_alloc 做任何事情。
  • @user1346994 我稍微更新了答案,希望对您有所帮助。
【解决方案2】:

错误消息准确地告诉您发生了什么以及该做什么:异常不能传播到事件处理程序(或信号/槽机制内的任何东西)之外,为了正确处理异常,必须捕获它们在QApplication::notify() 里面,像这样:

bool MyApplication::notify( QObject* receiver, QEvent* event )
{
    try {
        return QApplication::notify( receiver, event );
    } catch ( std::exception& e ) {
        cout << "Arrrgggghhhh" << endl;
        return false;
    }
}

此外,决定您可以拥有多少堆空间的是您的操作系统,而不是 Qt。

【讨论】:

  • 谢谢。我会测试一下。还要感谢您指出限制堆空间的是操作系统而不是 Qt。
【解决方案3】:

您不需要通过执行if(pixelvalue) 来检查pixelvalue 的完整性,如果new 失败,则会引发异常并且指针未分配到任何地方,因此pixelvalue 不存在,因此它对检查不存在的指针的完整性。如果您想检查它是否不是 NULL 指针,请使用它。

【讨论】:

  • pixelvalue 在构造函数中被初始化为指向 0。如果分配失败,pixelvalue 不会指向任何地方,这仍然是真的吗?
  • @Amani:这应该是一条评论; @user1346994:如果 new 运算符失败,它会抛出异常,因此您甚至无法测试指针值。
  • 我是新用户,只能评论自己的帖子
猜你喜欢
  • 1970-01-01
  • 2017-08-08
  • 1970-01-01
  • 1970-01-01
  • 2020-06-22
  • 1970-01-01
  • 2019-09-13
相关资源
最近更新 更多