82

私の C++ メソッドが奇妙なことに遭遇し、回復できない場合に、例外をスローしたいと考えています。std::stringポインタを投げても大丈夫ですか?

私が楽しみにしていたことは次のとおりです。

void Foo::Bar() {
    if(!QueryPerformanceTimer(&m_baz)) {
        throw new std::string("it's the end of the world!");
    }
}

void Foo::Caller() {
    try {
        this->Bar(); // should throw
    }
    catch(std::string *caught) { // not quite sure the syntax is OK here...
        std::cout << "Got " << caught << std::endl;
    }
}
4

7 に答える 7

102

はい。std::exceptionC++ 標準ライブラリの基本例外クラスです。文字列自体が使用中に例外をスローする可能性があるため、文字列を例外クラスとして使用することは避けたい場合があります。そうなったら、あなたはどこにいますか?

boost には、例外とエラー処理の優れたスタイルに関する優れたドキュメントがあります。一読の価値ありです。

于 2008-09-25T17:16:46.230 に答える
66

いくつかの原則:

  1. std::exception 基本クラスがある場合は、そこから例外を派生させる必要があります。そうすれば、一般的な例外ハンドラーにはまだいくつかの情報があります。

  2. ポインターではなくオブジェクトをスローしないでください。そうすれば、メモリが処理されます。

例:

struct MyException : public std::exception
{
   std::string s;
   MyException(std::string ss) : s(ss) {}
   ~MyException() throw () {} // Updated
   const char* what() const throw() { return s.c_str(); }
};

そして、それをコードで使用します。

void Foo::Bar(){
  if(!QueryPerformanceTimer(&m_baz)){
    throw MyException("it's the end of the world!");
  }
}

void Foo::Caller(){
  try{
    this->Bar();// should throw
  }catch(MyException& caught){
    std::cout<<"Got "<<caught.what()<<std::endl;
  }
}
于 2008-09-25T17:12:37.020 に答える
25

これらはすべて機能します。

#include <iostream>
using namespace std;

//Good, because manual memory management isn't needed and this uses
//less heap memory (or no heap memory) so this is safer if
//used in a low memory situation
void f() { throw string("foo"); }

//Valid, but avoid manual memory management if there's no reason to use it
void g() { throw new string("foo"); }

//Best.  Just a pointer to a string literal, so no allocation is needed,
//saving on cleanup, and removing a chance for an allocation to fail.
void h() { throw "foo"; }

int main() {
  try { f(); } catch (string s) { cout << s << endl; }
  try { g(); } catch (string* s) { cout << *s << endl; delete s; }
  try { h(); } catch (const char* s) { cout << s << endl; }
  return 0;
}

g よりも f よりも h を優先する必要があります。最も好ましくないオプションでは、メモリを明示的に解放する必要があることに注意してください。

于 2008-09-25T17:14:32.117 に答える
8

おそらく std::exception から派生したものをスローすることに加えて、匿名の一時オブジェクトをスローし、参照によってキャッチする必要があります。

void Foo::Bar(){
  if(!QueryPerformanceTimer(&m_baz)){
    throw std::string("it's the end of the world!");
  }
}

void Foo:Caller(){
  try{
    this->Bar();// should throw
  }catch(std::string& caught){ // not quite sure the syntax is ok here...
    std::cout<<"Got "<<caught<<std::endl;
  }
}
  • 匿名の一時オブジェクトをスローして、スローするオブジェクトの有効期間をコンパイラが処理できるようにする必要があります。新しいものをヒープからスローすると、他の誰かがそのオブジェクトを解放する必要があります。
  • オブジェクトのスライスを防ぐために参照をキャッチする必要があります

.

詳細については、Meyer の「Effective C++ - 3rd edition」を参照するか、https://www.securecoding.cert.org/.../ERR02-A.+Throw+anonymous+temporaries+and+catch+by+referenceにアクセスしてください。

于 2008-09-25T18:48:34.810 に答える
8

それはうまくいきますが、私があなただったらそうしません。完了時にそのヒープ データを削除していないようです。これは、メモリ リークが発生したことを意味します。C++ コンパイラは、スタックがポップされても例外データが存続することを保証するため、ヒープを使用する必要があるとは感じないでください。

ちなみに、投げることstd::stringは最初から最善の方法ではありません。単純なラッパー オブジェクトを使用すると、将来的にはより多くの柔軟性が得られます。今のところカプセル化するだけstringかもしれませんが、将来的には、例外の原因となったデータや行番号など、他の情報を含めたいと思うかもしれません (非常に一般的です)。コードベースのすべての場所ですべての例外処理を変更したくないので、今すぐ高い道を進み、生のオブジェクトをスローしないでください。

于 2008-09-25T17:09:32.677 に答える