web-dev-qa-db-ja.com

文字列リテラルをスローする場合、どのタイプをキャッチする必要がありますか?

私はLinuxでg ++を使用してC++で非常に単純なアプリケーションを作成しており、例外としていくつかの生の文字列をスローしようとしています(はい、私は知っています、それは良い習慣ではありません)。

私は次のコードを持っています(簡略化):

int main()
{
  try
  {
    throw "not implemented";

  }
  catch(std::string &error)
  {
    cerr<<"Error: "<<error<<endl;
  }
  catch(char* error)
  {
    cerr<<"Error: "<<error<<endl;
  }
  catch(...)
  {
    cerr<<"Unknown error"<<endl;
  }
}

そして、コンソールにUnknow errorが表示されます。しかし、リテラル文字列をstd::stringまたはchar *のいずれかに静的にキャストすると、期待どおりにError: not implementedが出力されます。私の質問は、静的キャストを使用したくない場合にキャッチする必要があるタイプは何ですか?

22
Grzenio

char const*ではなくchar*でキャッチする必要があります。 std::stringchar*のようなものはそれをキャッチしません。

キャッチには、一致するタイプに関するルールが制限されています。仕様によると(「cv」は「const/volatileの組み合わせ」を意味するか、どちらも意味しません)。

ハンドラーは、次の場合にタイプEの例外オブジェクトに一致します。

  • ハンドラーのタイプがcvTまたはcvT&であり、EとTが同じタイプ(最上位のcv修飾子を無視)であるか、または
  • ハンドラーはタイプcvTまたはcvT&であり、TはEの明確なパブリック基本クラスです。
  • ハンドラーはタイプcv1T * cv2であり、Eはポインタータイプであり、次のいずれかまたは両方によってハンドラーのタイプに変換できます。

    • プライベートクラス、保護されたクラス、またはあいまいなクラスへのポインタへの変換を含まない標準のポインタ変換(4.10)
    • 資格の変換

文字列リテラルの型はchar const[N]ですが、配列をスローすると配列が減衰し、実際には最初の要素へのポインタがスローされます。したがって、スローされた文字列リテラルをchar*でキャッチすることはできません。これは、一致するときにchar*char const*に一致させる必要があるためです。これにより、const(修飾)が破棄されます。変換はadd const)にのみ許可されます。文字列リテラルのchar*への特別な変換は、文字列リテラルを具体的に変換する必要がある場合にのみ考慮されます。

キャッチしているタイプにconstを追加してみてください。const char*(おそらくconst char* const)。

10
luke

文字列リテラルの正確なタイプは、const文字の配列です(たとえば、NULターミネータが含まれているため、const char [15])。配列は、スローされるとconst char*に減衰します。これは、長さに関係ありません。

4
Ben Voigt

タイプは_const char[15]_または_const char*_である必要があります。

ただし、言語では型の値をスローすることは禁止されていませんが、例外としてネイティブデータ型を発生させるべきではありません。代わりに、std::exception()インスタンスを発生させるか、独自の例外クラスを作成する必要があります。

1
vz0

問題は、constである何かをキャッチしようとしていることです。以下が機能します。

1
Wes Hardaker

文字列リテラルのタイプはchar const *です。既存のコードとの下位互換性のために、char *への(非推奨の)変換が提供されています(ただし、それでもconstとして扱う必要があります-変​​更しようとするとUBになります)。

そのため、次のようなコードが機能するはずです。

#include <iostream>
using namespace std;

int main()
{
  try
  {
    throw "not implemented";

  }
  catch(char const *error)
  {
    cerr<<"Error: "<<error<<endl;
  }
  return 0;
}
1
Jerry Coffin

標準仕様のセクション2.14.5を確認してください。これは、3ページの文字列リテラルのタイプと種類を扱います。あなたが始めたことをしないでください、ただ言ってください:

throw std::exception("not implemented");

適切なと一緒に

catch (std::exception& pEx)

この「通常の」アプローチに何か問題がありますか...?

1
Paul Michalik