【问题标题】:Handle exception when allocating object in Qt在 Qt 中分配对象时处理异常
【发布时间】:2012-03-19 21:32:34
【问题描述】:

对该主题进行了一些阅读,但无法得出结论。如果我试图在堆上分配一个 QFile(例如)并且如果文件抛出某种异常,我想丢弃它并继续处理下一个对象(恢复不会成为问题)。我的一些代码如下所示:

void FileUploader::uploadNext() {
    if(!canceled_) {

        if((iterator_ + 1) < (start_ + offset_)) {
            iterator_++;

            _mutex.lock();// lock the fileList for the other threads. 
            fileList_[iterator_].uploadStarted();

            try {
                _item = new QFile((fileList_.at(iterator_).fileInfo()).filePath());

            } catch(std::bad_alloc) {
                // emit error
                // log
                _mutex.unlock();
                return uploadNext(); // upload next
            }
                            // in setupInfoFile I also want to try-catch so I dont set the objects properties if it wasen't allocated. 
            InfoFile *temp = this->setupInfoFile("test", fileList_.at(iterator_).fileInfo(), false);

            if(temp != NULL) {
                temp ->setSomething("test")
                _mutex.unlock();
                                    // send the file to a networkAccessManager that will come back with signals 
                _realFileUploader->addFile(temp, _item);

            } else {

                _mutex.unlock();
                _item->deleteLater();

                // emit error
                // log

                return uploadNext();
            }

            emit statusChangedAt(iterator_);

        } else emit finished();
    } else emit canceled();
}

这里我有一个共享列表(与其他线程共享,因此是锁定的),我将逐步执行并创建两个我将尝试上传的对象。如果它无论如何都失败了,我想从中恢复并上传下一个项目。我该怎么做?

阅读 Qt 文档后,如果分配失败,某些对象只会返回 Null 指针,因为某些操作系统甚至不会抛出 bad_alloc 异常。他们还建议将 try-catch 块放在 main 周围,该块将处理有关例如内存的任何异常,然后让应用程序退出。我不想要那个。

那么在这种情况下我该如何处理异常或进行错误处理呢? Qt这句话是什么意思?

目前,从 Qt 中抛出的异常(例如由于内存不足)中恢复的唯一受支持用例是退出事件循环并在退出应用程序之前进行一些清理。

谢谢!

另外:这可能是一个非常愚蠢的问题,但是如果我在函数的堆栈上创建一个 QMutexLocker,当发生错误时会超出范围,那么锁定有多深?锁定是否像堆栈上的普通变量一样工作,因为它也不会锁定被调用函数中的内容?

【问题讨论】:

  • 这里的问题是,如果你不能为一个 QFile 分配空间,你很可能在下一个 QFile 上也会失败。
  • 那么我应该在为 QFile 分配时捕获任何东西还是应该让应用程序优雅地死掉?
  • 另外,如果我没有捕捉到异常,互斥锁会被解锁还是会死锁?

标签: c++ qt exception-handling


【解决方案1】:
    1234563 并且 Qt,除非您要使用的特定函数的文档另有说明,否则如果对 malloc 的内部调用失败,则抛出 bad_alloc 异常,这可能是它抛出的唯一类型异常。
  1. 你引用的那句话可能意味着当一个异常发生并且在到达事件循环之前没有被捕获时,你接下来唯一可以捕获它的地方是在exec()调用周围。

  2. QMutexLocker 旨在分配在堆栈上,并在变量超出范围时解锁互斥锁(请参阅the RAII idiom)。
    您可能还应该将任何原始指针包装在智能指针中(例如:QScopedPointerQSharedPointer 或其数组变体),以便在您未到达范围末尾时自动释放它们,因为发生异常。

尽管如此,并且不尝试捕获异常,因为任何进一步的内存分配都可能会失败,所以您的代码将如下所示:

void FileUploader::uploadNext()
{
    if(canceled_) {
        emit canceled();
        return;
    }

    if ( ++iterator_ >= (start_ + offset_)) {
        emit finished();
        return;
    };

    QMutexLocker locker(mutex);
    fileList_[iterator_].uploadStarted();

    QScopedPointer<QFile> item(
       new QFile((fileList_.at(iterator_).fileInfo()).filePath()));

    QScopedPointer<InfoFile> temp(
        this->setupInfoFile("test", fileList_.at(iterator_).fileInfo(), false));

    temp->setSomething("test")    
    _realFileUploader->addFile(temp.data(), item.data());

    // remove the pointer from the QScopedPointers guard
    temp.take();
    item.take();

    emit statusChangedAt(iterator_);
}

【讨论】:

  • 我将 mutexlocker 更改为将超出范围的 QMutexLocker locker(&mutex)。有没有其他方法可以毫无例外地处理这个特殊问题?也许 std::nothrow 并检查空指针?
  • 您分配的任何 QString 都可能引发异常,您唯一能做的就是大量使用 RAII 习语编写异常安全代码。如果你使用 nothrow 并测试 null,正常的执行路径对于任何阅读你的代码的人来说都不太清楚,并且由于显式测试而慢了一点。
  • 但是现在指向文件的指针会在超出范围时消失,对吗? fileUploader 使用将上传文件的 QNetworkAccessManager,这意味着我需要两个对象都处于活动状态并一直运行,直到请求完成。
  • 只有在指针超出范围之前没有调用 take 时,它们才会被删除。使用QSharedPointer 可能会更容易,如果addFile 函数也使用QSharedPointer 而不是原始指针,因为您不必手动调用take(以向指针添加引用计数器为代价) .
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-02
相关资源
最近更新 更多