2010-11-20 7 views
2

私の最後の2つのプロジェクトでは、「すべてのメソッド/関数はいくつかの一般的なERROR_CODE型を使用してエラーコードを返すべきです」という奇妙なガイドラインを見てきました。どちらのプロジェクトでも、ERROR_CODEはint型typedefです。奇妙なパターン:すべての関数/メソッドは、C++で同じ型を使用してエラーコードを返します

C++で行う理由はありますか?いくつかのMISRA要件またはそのようなものはありますか?

私は唯一の欠点を見ることができます:

  • 関数は値を返す必要がある場合は、それは引数の参照によって行われます。例:

    文字列s; ERROR_CODE err = getString(s);

  • 機能の重要性は明白ではありません。すべて同じように見えます。エラーのリストには、低レベルエラーからドメイン固有のエラーまでの何百ものエラーが含まれています。

あなたはこのプログラミングスタイルを経験していますか?それに対して、またはそれに対して良い議論があるか?

+0

(Windows)NTを見てください。すべてのシステムコールとその他の関数は、NTSTATUS値を返します。 – wj32

答えて

3

私はそれはいくつかの理由で非常に悪いスタイルだと思う。

  1. これまで説明したように、関数の実際の結果を格納するポインタ/参照を渡す必要があります。
  2. あなたが言いましたように、統一されたエラーコードはあらゆる種類のドメインからあらゆる種類のエラーを統一しようとしているので醜いです。
  3. エラーコードシステム上のすべてのプログラムモジュールの人為的な依存関係を作成し、他のプログラムのモジュールの単一サブモジュールまたは小さなサブセットを再利用することを厄介にします。
  4. さらに、エラーコードのいくつかはドメイン固有であるため、実際には関連していないオブジェクトタイプ/モジュール間の依存関係が導入されています。それらはすべて、すべてのエラータイプの和集合に依存するコンポーネントに依存します。

私の見解では、管理可能な方法の数が少なすぎると失敗する可能性がある関数/メソッドは、過度に複雑であるか、またはおそらくは両方が原因である可能性があります。

本当にエラーコードを返す場合、私は物事を交換し、関数の引数としてエラーコードへのポインタを渡し、実際の結果を戻り値にします。それから私は、エラーコードを実装するためのこれら2つのアプローチのいずれかを選択します:

  1. 簡単な方法:離れエラーコードのすべての抽象化を投げると、単にいくつかの汎用エラークラスにintを使用しています。
  2. 重いオブジェクト指向の方法:基本クラスが非常に抽象的であり、依存性を導入することなくすべてのコンポーネント間で共有できる内部 "エラーオブジェクト"へのポインタを提供し、各コンポーネントが独自のコンポーネント固有のエラーオブジェクト必要に応じて。

より良いアプローチは、おそらく例外を使用することだろうC++を使用している場合...

+0

良い点、ありがとうございます!どちらのプロジェクトでも、例外は使用しないでください。 :-(私は、統一されたエラーコードのルールの理由もあると思います。返す無効な値は決してありません。通常、例外によって通知します。 –

1

私はそれを見ました。

カーネルプログラミングは、1つのエラーだけが可能な場合を除いて、そうです。

素晴らしいアイデアのように聞こえるわけではありませんが、1つ悪いことはありません。

1

チームがエラーを返す共通の手段に同意することは珍しいことではありません。これは他のチーム全体のコーディング規則と同じように、プロジェクトのコードに共通の「ルックアンドフィール」を作り出すのに役立ちます。これは、新しいチームメンバーが全体像をより早く理解し、チーム内の他の人々のコードをより直感的に保守するのに役立ちます。

私はC++プロジェクトが例外ではなくエラーの背後に統合されていることは驚くべきことです。例外とエラーコードhereの長所と短所についての議論があります。

私は、このアプローチ(咳... Win32 ...咳)につながるCスタイルのAPIを使用している場合は、エラーコードの処理に有利な1つの引数と思います。

1

このイディオムは、特にCの世界では、非常に一般的です。

私はそれを自分で使用していないにもかかわらず、それは良い(より多くの答えは他の回答)よりも害を及ぼすと思うが、私はそれの利点を見つける:一貫性のある方法で呼び出しに予期しないエラーを報告するサイト。 errno変数のようなものですが、使いやすいものです。例えば

、関数の集合を考える:

int a(); 
std::string b(); 
double c(); 
std::list<long> d(); 

上記の各機能は、異なる方法で失敗したことを示すであろう:()は-1、B()空の文字列を返すことができ、 c()a 0.0およびd()は空のリストです。それは一貫性がなく、直感的ではありません。今度は、その範囲が返すタイプの可能な範囲全体をカバーする関数を想像してください。それはさらに悪いことです。

int x(bool* ok); 

をしかし、それはまた、追加の引数を持つ各機能を汚染:

一部のAPIも行います。

Cでは、さまざまな種類のエラーを示すようなAPIを実際に設計する必要がある場合は、うまくいく可能性はあまりありません。しかし、C++の世界では、例外を使うことができます。

+0

このアプローチは、C++では最適ではないと思います。ある種類のバリアントクラスを返し、無効な値を返します(バリアントクラスのbool isValid()const;メソッドを提供するなど)。タイプの1つの「マジック」値によるエラーを示すことは非常に貧弱なスタイルです。 –

1

私は、バイナリをコンパイルするのに使われている以外の別のコンパイラでコンパイルされたC++ライブラリにリンクするとき、例外が機能しない可能性があることを見てきました。この非作業は完全に真実かもしれませんが、実際には、リンクプロセスでさえ(すべての人が標準に固執しているかもしれませんが)必要はないので、理論的には、この議論は無効です。実際には、となります(私はここでの経験はありません)。その名前のマングリングの競合はほとんど起こりません。アラインメントの競合はほとんど発生せず、例外を除いて、 。

私が見た第2引数は、実行時のパフォーマンスです。 の例外の場合のスタック解舒時間は、ですが、現実的な量のリターンコードチェックと例外を比較した公正なベンチマークはまだありません。

私の典型的なC++ではミックスを使用しています。私は頻繁に起こるとは思っていないものや、ほとんど実行されないことが測定されたパスを除外し、頻繁に呼び出される可能性が高いもののコードを返します。 すべての反復でいくつかの面白い条件が成り立つので、タイトなループ内で例外をスローすることは安くはありません(ループ本体がそれを処理していると仮定します)。

+0

Windowsでは、したがって、例外のみが異なる可能性があります。 – Joshua