2010-12-05 64 views
20

我有這樣的代碼..手動拋出std :: bad_alloc可以嗎?

CEngineLayer::CEngineLayer(void) 
{ 
    // Incoming creation of layers. Wrapping all of this in a try/catch block is 
    // not helpful if logging of errors will happen. 

    logger = new (std::nothrow) CLogger(this); 

    if(logger == 0) 
    { 
    std::bad_alloc exception; 
    throw exception; 
    } 

    videoLayer = new (std::nothrow) CVideoLayer(this); 

    if(videoLayer == 0) 
    { 
    logger->log("Unable to create the video layer!"); 

    std::bad_alloc exception; 
    throw exception; 
    } 
} 

IEngineLayer* createEngineLayer(void) 
{ 
    // Using std::nothrow would be a bad idea here as catching things thrown 
    // from the constructor is needed. 

    try 
    { 
    CEngineLayer* newLayer = new CEngineLayer; 

    return (IEngineLayer*)newLayer; 
    } 
    catch(std::bad_alloc& exception) 
    { 
    // Couldn't allocate enough memory for the engine layer. 
    return 0; 
    } 
} 

我省略了大部分的非相關的信息,但我認爲這幅畫是在這裏清楚。

是否可以手動拋出std :: bad_alloc而不是單獨嘗試/捕獲所有圖層創建,並在重新拋出bad_allocs之前進行記錄?

+0

小記,如果你沒有使用智能指針記錄器,那麼這將泄漏,如果CVideoLayer的構造函數拋出。 – 2010-12-05 12:00:59

+0

我編輯了視頻圖層部分,因爲我實際上沒有視頻圖層,但想要顯示我的問題。我決定簡單而不是準確。 – Jookia 2010-12-05 13:30:03

回答

18

你不需要那樣做。您可以使用throw語句的參數的形式趕上std::bad_alloc例外,記錄它,然後重新拋出:

logger = new CLogger(this); 
try { 
    videoLayer = new CVideoLayer(this); 
} catch (std::bad_alloc&) { 
    logger->log("Not enough memory to create the video layer."); 
    throw; 
} 

或者,如果logger不是智能指針(它應該是):

logger = new CLogger(this); 
try { 
    videoLayer = new CVideoLayer(this); 
} catch (std::bad_alloc&) { 
    logger->log("Not enough memory to create the video layer."); 
    delete logger; 
    throw; 
} catch (...) { 
    delete logger; 
    throw; 
} 
+0

+1;這樣做 - 讓異常爲你工作;不適用於例外情況。 – 2010-12-05 07:05:30

1

另一種模式是使用的事實記錄是受RAII,太:

CEngineLayer::CEngineLayer() 
{ 
    CLogger logger(this); // Could throw, but no harm if it does. 
    logger.SetIntent("Creating the video layer!"); 
    videoLayer = new CVideoLayer(this); 
    logger.SetSucceeded(); // resets intent, so CLogger::~CLogger() is silent. 
} 

了清晰秤是否有MULTIP le步驟。您只需重複撥打.SetIntent即可。通常,您只寫出CLogger::~CLogger()中的最後一個意圖字符串,但對於額外的詳細日誌記錄,您可以寫出所有意向。

順便說一句,在你的createEngineLayer你可能想要一個catch(...)。如果記錄器拋出DiskFullException會怎麼樣?

30

只是爲了回答這個問題(因爲沒有其他人似乎已經回答了這個問題),在C++ 03標準定義std::bad_alloc如下:

namespace std { 
    class bad_alloc : public exception { 
    public: 
    bad_alloc() throw(); 
    bad_alloc(const bad_alloc&) throw(); 
    bad_alloc& operator=(const bad_alloc&) throw(); 
    virtual ˜bad_alloc() throw(); 
    virtual const char* what() const throw(); 
    }; 
} 

由於標準定義的公共構造函數,你會完全安全地構建並從代碼中拋出一個。 (任何具有公共拷貝構造函數的對象都可以拋出,IIRC)。

5

如果我在STL容器中使用一些自定義分配器,我個人會拋出它。這個想法是爲STL庫提供與默認的std :: allocator相同的接口,包括行爲方面的接口。因此,如果你有一個自定義的分配器(比如從內存池中分配一個)並且底層分配失敗,請調用「throw std :: bad_alloc」。這保證了99.9999%的時間是一些STL容器的調用者將正確地調用它。如果分配器返回一個大胖子0,你無法控制那些STL實現將會執行什麼操作 - 它不可能是任何你喜歡的東西。

相關問題