注:私はここで悪魔の擁護者やそのようなものを演奏していません-私はこのキャンプに自分自身がないので、本当に純粋に興味があります。
標準ライブラリのほとんどの型には、例外をスローできる変更関数(たとえば、メモリ割り当てが失敗した場合)または例外をスローできる非変更関数(たとえば、範囲外のインデックス付きアクセサー)があります。それに加えて、多くの無料の関数は例外をスローできます(たとえば、operator new
およびdynamic_cast<T&>
)。
どのように実用的に「例外を使用しない」という文脈でこれに対処しますか?
neverスローできる関数を呼び出しようとしていますか? (それがどのようにスケーリングされるかはわかりませんので、これが当てはまる場合、どのようにこれを達成するのか非常に興味があります)
標準ライブラリを投げても大丈夫ですか。「例外を使用しません」を「throwourコードからの例外であり、catchother's code "からの例外?
コンパイラスイッチを介して例外処理を完全に無効にしますか?もしそうなら、標準ライブラリの例外を投げる部分はどのように機能しますか?
[〜#〜] edit [〜#〜]コンストラクター、失敗するか、慣例により、失敗時にエラーコードを返すことができる専用のinit関数を持つ2ステップ構成を使用しますか(コンストラクターができない)、または何か他のことをしますか?
[〜#〜] edit [〜#〜]質問の開始から1週間後の軽微な説明...以下のコメントおよび質問の内容の多くはwhy =例外の側面と「他の何か」。私の興味はそれではありませんが、whenあなたが「何か他のこと」を行うことを選択した場合、howdo例外をスローしますか?
私は自分自身と世界の隅々に答えます。私はc ++ 14(コンパイラーのサポートが改善されると17になります)を作成します。ルールセットは次のとおりです。
メモリはプールされ、事前に割り当てられているため、初期化後にmalloc呼び出しはありません。データ構造は不滅または簡単にコピーできるため、デストラクタはほとんど存在しません(スコープガードなどの例外がいくつかあります)。基本的に、C +タイプセーフティ+テンプレート+ラムダを実行しています。もちろん、例外はコンパイラスイッチを介して無効にされます。 STLに関しては、その良い部分(つまり、アルゴリズム、数値、type_traits、反復子、アトミック、...)はすべて使用可能です。例外をスローする部分は、ランタイムメモリ割り当て部分とセミOO部分とうまく一致するため、ストリーム、std :: array、std :: stringを除くコンテナをすべて一度に取り除くことができます。
どうしてですか?
この場合、コンパイラーを介して例外を無効にします(gccの場合は-fno-exceptions
)。
Gccの場合、_GLIBCXX_THROW_OR_ABORT
と呼ばれるマクロを使用します。
#ifndef _GLIBCXX_THROW_OR_ABORT
# if __cpp_exceptions
# define _GLIBCXX_THROW_OR_ABORT(_EXC) (throw (_EXC))
# else
# define _GLIBCXX_THROW_OR_ABORT(_EXC) (__builtin_abort())
# endif
#endif
(最新のgccバージョンのlibstdc++-v3/include/bits/c++config
にあります)。
次に、スローされた例外が中止されるという事実に対処する必要があります。それでもシグナルをキャッチしてスタックを印刷することができます(SOでこれを説明している)には良い答えがあります)が、この種のことは(少なくともリリースでは)避けるべきです。
何か例を挙げたい場合は、
try {
Foo foo = mymap.at("foo");
// ...
} catch (std::exception& e) {}
できるよ
auto it = mymap.find("foo");
if (it != mymap.end()) {
Foo foo = it->second;
// ...
}
また、例外を使用しないことについて尋ねるとき、標準ライブラリに関するより一般的な質問があることを指摘したいと思います。Are yo例外」キャンプ?
標準ライブラリは重いです。たとえば、多くのGameDev企業のように、一部の「例外を使用しません」キャンプでは、STLに適した代替手段が使用されます-主にEASTLまたはTTLに基づいています。とにかく、これらのライブラリは例外を使用しません。これは、第8世代のコンソールが例外をあまりにも(またはまったく)処理しなかったためです。最先端のAAAプロダクションコードの場合、例外はとにかく重すぎるので、このような場合の勝ち組シナリオです。
言い換えれば、多くのプログラマーにとって、例外をオフにすることは、STLをまったく使用しないこととペアになります。
注私は例外を使用しています...しかし、私は強制されていません。
スローできる関数を呼び出さないようにしていますか? (それがどのようにスケーリングされるかはわかりませんので、これが当てはまる場合、どのようにこれを達成するのか非常に興味があります)
これはおそらく、少なくとも大規模には実行不可能です。多くの関数は投げることができますが、コードベースを完全に損なうことは避けてください。
標準ライブラリを投げても大丈夫ですか?「例外を使用しません」を「コードから例外をスローせず、他のコードから例外をキャッチしない」として扱いますか?
ライブラリコードが例外をスローし、コードがそれを処理しない場合、終了がデフォルトの動作です。
コンパイラスイッチを介して例外処理を完全に無効にしますか?もしそうなら、標準ライブラリの例外を投げる部分はどのように機能しますか?
これは可能です(以前は、一部のプロジェクトタイプで人気があったこともあります)。コンパイラはこれをサポートしている/サポートしている可能性がありますが、結果がどのようなものになる可能性があるのか(およびその条件下でどの言語機能がサポートされるのか)についてドキュメントを参照する必要があります。
一般に、例外がスローされる場合、プログラムは中止するか、終了する必要があります。一部のコーディング標準ではまだこれが必要です。JSFコーディング標準が思い浮かびます(IIRC)。
「例外を使用しない」ユーザー向けの一般的な戦略
ほとんどの関数には、一連の前提条件があり、呼び出しの前にをチェックできます。それらを確認してください。満たされていない場合は、電話をかけないでください。そのコードのエラー処理が何であれ、フォールバックします。前提条件が満たされていることを確認するためにチェックできない関数については、それほどではありませんが、プログラムは中止される可能性があります。
例外をスローするライブラリを回避する-標準ライブラリのコンテキストでこれを尋ねたので、これはありません法案に完全に適合しますが、オプションのままです。
その他の可能な戦略。これは些細に聞こえるかもしれませんが、それらを使用しない言語を選択してください。 Cはうまくできました...
...私の質問の要点(もしあれば、標準ライブラリとの相互作用)、私はあなたのコンストラクタについて聞いてみたいです。それらは失敗する可能性がありますか、または慣例により、失敗時にエラーコードを返すことができる(コンストラクターができない)専用のinit関数を持つ2ステップ構成を使用していますか?それとも、あなたの戦略は何ですか?
コンストラクターを使用する場合、通常、障害を示すために使用される2つのアプローチがあります。
enum
を設定して、障害とその障害を示します。これは、オブジェクトの構築と適切なアクションが行われた後に調査できます。init()
メソッドを使用して、構築を実行(または完了)します。失敗した場合、メンバーメソッドはエラーを返すことができます。init()
テクニックの使用は、内部の「エラー」コードよりも連鎖可能であり、拡張性が高いため、一般的に好まれます。
繰り返しになりますが、これらは例外が存在しない環境(Cなど)に由来する手法です。 C++などの言語を例外なく使用すると、その使いやすさと標準ライブラリの幅広さの有用性が制限されます。
あなたが尋ねた質問に完全に答えようとするのではなく、エラーを処理するメカニズムとして例外を利用しないコードベースの例として、Googleを挙げます。
Google C++コードベースでは、失敗する可能性のあるすべての関数は、呼び出し先の結果を指定するstatus
などのメソッドを持つok
オブジェクトを返します。
開発者がreturn status
オブジェクトを無視した場合、コンパイルに失敗するようにGCCを設定しました。
また、彼らが提供する小さなオープンソースコード(LevelDBライブラリなど)からは、とにかくSTLをあまり使用していないようであるため、例外処理はまれになります。 Titus WintersがCPPConでの講義で述べているように、彼らは「標準を尊重しますが、それを偶像化しないでください」。
これは態度の質問だと思います。 「何かが失敗しても気にしない」という陣営にいる必要があります。これは通常、コードを生成します。そのためには、なぜ突然何かが機能しなくなったのかを見つけるために(顧客サイトで)デバッガーが必要です。また、この方法でソフトウェアの「エンジニアリング」を行う可能性のある人々は、非常に複雑なコードを使用しないでください。例えば。依存するすべてのn個のリソースが(これらのリソースにRAIIを使用して)正常に割り当てられた場合にのみ実行されるという事実に依存するコードを書くことはできません。したがって、このようなコーディングは、次のいずれかとなります。
ここで、最新のコードについて説明していることに注意してください。顧客提供のdllをオンデマンドで読み込み、子プロセスを使用しています。何かが失敗する可能性のある多くのインターフェースがあります。私はgrep/more/ls/findの一部の置き換えについては話していません。