web-dev-qa-db-ja.com

c ++例外:std :: stringをスローしています

私の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;
    }
}
72
Palad1

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

boostには優れた document があり、例外とエラー処理に適したスタイルです。読む価値があります。

97
christopher_f

いくつかの原則:

  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;
  }
}
59
PierreBdR

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

#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;
}

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

21
anon

おそらく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+にアクセスしてください。参照

7
Michael Burr

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

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

7
Daniel Spiewak

C++で例外をスローする最も簡単な方法:

#include <iostream>
using namespace std;
void purturb(){
    throw "Cannot purturb at this time.";
}
int main() {
    try{
        purturb();
    }
    catch(const char* msg){
        cout << "We caught a message: " << msg << endl;
    }
    cout << "done";
    return 0;
}

これは印刷します:

We caught a message: Cannot purturb at this time.
done

スローされた例外をキャッチすると、例外が含まれ、プログラムが続行されます。例外をキャッチしなかった場合、プログラムが存在し、出力されます:

This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information.

4
Eric Leschinski

この質問はかなり古く、すでに回答されていますが、適切な例外処理を行う方法に関するメモを追加したいだけですin C++ 11

つかいます - std::nested_exception および std::throw_with_nested

私の意見では、これらを使用すると、例外の設計がよりクリーンになり、例外クラス階層を作成する必要がなくなります。

これにより、デバッガーや面倒なロギングを必要とせずに、コード内で例外のバックトレースを取得できることに注意してください。 StackOverflow here および here で、ネストされた例外を再スローする適切な例外ハンドラーを記述する方法について説明します。

派生した例外クラスでこれを行うことができるため、このようなバックトレースに多くの情報を追加できます!また、私の GitHubのMWE を見ると、バックトレースは次のようになります。

Library API: Exception caught in function 'api_function'
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"
1
GPMueller