std :: bad_allocを手動で投げることは大丈夫ですか?
-
08-10-2019 - |
質問
私はこのコードを持っています。
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;
}
}
私はほとんど関連していない情報のほとんどを省略しましたが、ここでは写真が明確だと思います。
すべてのレイヤー作成を個別に試してキャッチし、bad_allocsをre延する前にロギングする代わりに、手動でstd :: bad_allocを手動で投げることはできませんか?
解決
あなたはそれをする必要はありません。のパラメーターのない形式を使用できます throw
キャッチするための声明 std::bad_alloc
例外、それを記録してから、それをrethrowします:
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;
}
他のヒント
質問に答えるために(他の誰もそれに答えたようには見えないので)、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をスローできます)。
STLコンテナでカスタムアロケーターを使用している場合、私は個人的に投げます。アイデアは、デフォルトのSTD :: AllocatorとしてSTLライブラリに、動作の観点を含む同じインターフェイスを提示することです。
したがって、カスタムアロケーター(たとえば、メモリプールから割り当てられたもの)と基礎となる割り当ての失敗がある場合は、「stow std :: bad_alloc」を呼び出します。これにより、時間の99.9999%がSTLコンテナである発信者が適切にフィールドにフィールドを保証します。アロケーターが大きな脂肪0を返した場合、これらのSTL実装が何をするかを制御できません。
別のパターンは、ロガーが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.
}
複数のステップがある場合、これはきれいにスケールします。あなたはただ電話します .SetIntent
繰り返し。通常、あなたは最後の意図の文字列を書き出すだけです CLogger::~CLogger()
しかし、余分な冗長ロギングの場合、すべての意図を書き出すことができます。
ところで、あなたの中に createEngineLayer
あなたは欲しいかもしれません catch(...)
. 。ロガーがスローした場合はどうなりますか DiskFullException
?