2017-12-28 74 views
-2

私は例外を除いて問題ました:例外&Cスタイルの文字列

#include <iostream> 
#include <cstring> 
#include <exception> 

class except :public std::exception 
{ 
    char* err; 
public: 
    except(const char* s) noexcept 
    { 
     err = new char[strlen(s) + 1]; 
     strcpy(err, s); 
     err[strlen(s)] = 0; //is it necessary?? 
    } 
    virtual const char* what() noexcept 
    {return err;} 
    virtual ~except() noexcept 
    {delete err;} 
}; 

double div(const double& a, const double& b) noexcept 
{ 
    if (b == 0.0) 
     throw except("DIVIDED BY 0"); 
    return a/b; 
} 

int main() 
{ 
    try 
    { 
     std::cout << div(5.0, 0.0); 
    } 
    catch (std::exception &ex) 
    { 
     std::cout << ex.what(); 
    } 
    return 0; 
} 

を私は「0で除算し、」印刷したいが、私は得る:

terminate called after throwing an instance of 'except' 
    what(): std::exception 
Aborted 

Process returned 134 (0x86) 

は、私はすべての機能にnoexceptを入れましょう/例外をスローしないメンバ関数?

err[strlen(s)] = 0は必要ですか? (中(のconstのchar * sで)を除く以外::)

+1

?より良い:std :: runtime_errorから派生します。 –

+2

1)C文字列は何ですか?それらはヌルで終了する文字列です。 "[std :: strcpy](http://en.cppreference.com/w/cpp/string/byte/strcpy)以降、実際にはありません" _Is 'err [strlen(s)] = 0'が必要ですか?文字列をコピーするときにそれを含みます。しかし、そのような行は害を及ぼさない。 2) 'delete err;'は未定義の動作です。それは 'new []'で 'new'されたので、' delete [] err; 'として削除する必要があります。 –

+0

あなたは例外を使用していますが、これはC++のやや中級から上級のトピックですが、Cスタイルの文字列を使用しています。どうして? – PaulMcKenzie

答えて

2

私が "0で除算し、" 印刷したいが、私は得る:

double div(const double& a, const double& b) noexcept 
'以外' のインスタンスを投げた後に呼び出さTERMINATE

あなたは例外を投げないと主張していますが、あなたは嘘をついています。結果は、実際にスローするときにstd :: terminateを呼び出すことです。

+0

'noexcept'を削除した後、' ex.what() 'は' std :: exception'を返します。 ':public std :: exception'を':public std :: runtime_error'に変更した場合、それはなぜですか? – inter22

2

問題は実際には2倍です。まず、@ manni66が示唆しているように、divnoexceptと宣言してはいけません。これは実行時エラーの原因になりますが、それを削除しても問題は解決しません。

第二の問題は、whatが宣言されていることである。

それは次のように std::exceptionで宣言されています一方
virtual const char* what() noexcept; 

virtual const char* what() const noexcept; 

と署名の違いは、それがstd::exceptionのためのハンドラでキャッチだときことを意味std::exception::what()と呼びます。except::what()

言及する価値のあるポイント:

  1. 関数のオーバーロードが基本クラスのものと正確に一致することを確認してください。
  2. 特定の種類の例外がスローされることが予想される場合は、まず特定のハンドラでその例外をキャッチし、明示的に例外に適切な名前を使用してください。
  3. 可能であれば、他の人が触れたように、std::stringクラスを使用してみてください。物事をより簡単で安全にします。この場合、ポイント2は逃げるので、文字クラスメンバはそれ以上の資格を必要としないほど十分に固有であるため、実際には必要ありません。
  4. 特定の値を追加しない限り、例外クラスを作成しないでください(の値はですが、特定のタイプの例外を特定して特定の方法で処理したいことがあります)。一般的な例外である場合std::runtime_errorまたはこの場合はstd::overflow_errorが適切な選択肢になり、どちらもコンストラクタの引数としてstd::stringを受け取ります。したがって、独自の例外クラスを作成する必要はありません。たとえば、

#include <exception> 
using namespace std; 


class divide_by_zero : public std::exception 
{ 
public: 
    virtual const char* what() const noexcept { return "DIVIDED BY 0"; } 
}; 

double div(const double& a, const double& b) 
{ 
    if (b == 0.0) 
     throw divide_by_zero(); 
    return a/b; 
} 

int main() 
{ 
    try 
    { 
     std::cout << div(5.0, 0.0); 
    } 
    catch (divide_by_zero &ex) 
    { 
     std::cout << ex.what(); 
    } 
    catch (std::exception &ex) 
    { 
     std::cout << ex.what(); 
    } 
    return 0; 
} 

出力:あなたがのstd ::文字列を使用していないのはなぜ

DIVIDED BY 0 
+0

私はCスタイルの文字列を使用すべきではなく、必要でない場合は独自の例外クラスを作成しないでください。私はちょうどそれが働いていない理由を知りたい。 'noexcept'を追加しても問題は解決しません。出力はまだ' std :: exception'です。 (私は '' std :: runtime_error( "DIVIDED BY 0") 'を使用することができることを知っています) – inter22

+0

あなたのコードを取り、(a)' noexcept' _only_fron div関数を削除して、 what() 'は、上記の余分な提案がなくても' std :: exception'と全く同じシグネチャを持っています(つまりconstでなければなりません) –

関連する問題