2012-03-19 68 views
0

對該主題做了一些閱讀,但無法得出結論。如果我試圖在堆上分配一個QFile(例如),並且如果該文件正在拋出某種異常,我想放棄它並繼續處理下一個對象(恢復不會成爲問題)。我的一些代碼如下所示:在Qt中分配對象時處理異常

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文檔後,如果分配失敗,某些對象只會返回一個空指針,因爲某些操作系統甚至不會拋出bad_alloc異常。他們還建議將try-catch塊放在main中,這樣可以處理有關例如內存的任何異常,然後讓應用程序退出。我不想那樣。

那麼在這種情況下,我該如何處理異常或做錯誤處理呢? Qt對這句話意味着什麼?

目前,唯一支持的情況下使用用於從內Qt的拋出的異常(例如,由於出的存儲器)回收是退出事件循環和退出應用程序之前做一些清理。

謝謝!

另外:這可能是一個非常愚蠢的問題,但如果我將在函數的堆棧中創建一個QMutexLocker時,鎖定的程度有多深,當發生en錯誤時,它將超出範圍?鎖是否像堆棧中的普通變量一樣工作,它不會鎖定被調用函數中的東西?

+0

這裏的問題是,如果你不能爲一個QFile分配空間,你也可能會在下一個QFile上失敗。 – 2012-03-19 21:39:18

+0

因此,當我爲QFile分配時應該捕獲什麼,或者應用程序是否優雅地死去? – chikuba 2012-03-19 21:53:48

+0

另外,如果我不知道例外情況,互斥鎖會解鎖還是會陷入僵局? – chikuba 2012-03-19 21:58:46

回答

1
  1. 如果您分配了新的指針,和你有一個適度最近的編譯器,它應該在內存耗盡的情況下拋出一個異常std::bad_alloc。 和Qt,除非你想要使用的特定函數的文檔說不然,否則拋出bad_alloc例外,如果內部調用malloc失敗,這可能是唯一的類型異常拋出。

  2. 您引用的這句話可能意味着,如果發生異常並且在到達事件循環之前沒有捕獲到,那麼您可以在下一個捕獲它的唯一位置是調用exec()

  3. QMutexLocker意味着分配在堆棧上,並且當變量超出範圍時將解鎖互斥鎖(請參閱the RAII idiom)。
    您應該也可能將任何原始指針包裹在智能指針(例如:QScopedPointer,QSharedPointer或它們的數組變體)中,以便在發生異常時未到達範圍末尾時自動釋放它們。

有了這一切,並沒有試圖捕獲異常,因爲任何進一步的內存分配很可能無論如何失敗,你的代碼應該是這樣的:

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_); 
} 
+0

我將mutexlocker更改爲QMutexLocker更衣櫃(&mutex),它將超出範圍。有沒有其他辦法可以毫無例外地處理這個特殊問題?也許std :: nothrow並檢查nullpointer? – chikuba 2012-03-20 01:44:44

+0

您分配的任何QString都可以拋出異常,您唯一能做的就是大量使用RAII語言編寫異常安全的代碼。如果你使用nothrow和null來測試,那麼正常的執行路徑對於任何讀取你的代碼的人來說都不太清晰,而且由於明確的測試,它會慢一點。 – alexisdm 2012-03-20 02:00:32

+0

但是現在指向該文件的指針會在超出範圍時死亡? fileUploader使用QNetworkAccessManager來上傳文件,這意味着我需要這兩個對象都是活着的,然後踢,直到請求完成。 – chikuba 2012-03-20 02:14:42