4

私はcからc++クラスへの関数のportingfile-ioセットを書いています。「魔法の数」(名前のない定数)はたくさんあります。

関数は、場所が現在マジックナンバーで示されている特定のエントリの数を含むファイルヘッダーを読み取ります。

私は数年前にベテランプログラマーから「魔法の数字」を使用することは本質的に悪であると教えられました。そのため、ポートで名前のない定数を使用しないようにしました。そこで、エントリが格納されている場所の定数のリストを作成したいと思います。

これまでのところ、比較的安全と思われる2つのソリューションを考え出しました。名前空間で囲まれた定数のセットまたは名前空間で囲まれた列挙型を使用します。

どちらのソリューションも安全に使用できますか?どちらか一方に利点はありますか?

例:
オプション1

namespace hdr_pos {
   const unsigned int item_1_pos=4;
   const unsigned int item_2_pos=8;
   const unsigned int item_3_pos=12;
   const unsigned int item_4_pos=24;
   const unsigned int item_5_pos=32;
};

オプション2

namespace hdr_pos {
   enum e {
      item_1_pos=4,
      item_2_pos=8,
      item_3_pos=12,
      item_4_pos=24,
      item_5_pos=32
   };
};

重複を防ぎ、ファイルヘッダーの将来の更新のために位置を変更した場合にキャッチする方法はありますが、そのうちの1つを変更するのを忘れていますか?

この事実と非主観的なものを保管してください。あなたが知っている利点がない場合は、遠慮なく答えてください。

注:もちろん、実際の実装では、よりわかりやすい名前を使用します。例として、私は物事をitem _ <#>_...と呼びました...

4

5 に答える 5

2

列挙型を使用することには2つの利点があります。まず、一部のデバッガーは定数を列挙型変数名に変換し直すことができます(これにより、場合によってはデバッグが容易になります)。また、その列挙型の値のみを保持できる列挙型の変数を宣言することもできます。これにより、定数を使用するだけでは得られない、追加の形式の型チェックを行うことができます。

値が重複しているかどうかを確認することは、特定のコンパイラーによって異なる場合があります。これを行う最も簡単な方法は、列挙型定義を解析し、値が重複しているかどうかを報告する外部スクリプトを作成することです(必要に応じて、ビルドプロセスの一部としてこれを実行できます)。

于 2010-09-17T19:24:40.187 に答える
1

エラーコードについては、以前にこの状況に対処しました。

エラーコードに列挙型を使用している人を見たことがありますが、これにはいくつかの問題があります。

  1. どの値にも対応しない(あまりにも悪い)列挙型にintを割り当てることができます
  2. 値自体はヘッダーで宣言されます。つまり、エラーコードの再割り当て(これが発生します...)はコードの互換性を損ないます。要素を追加するときも注意する必要があります...
  3. 列挙型は「拡張」できないため、一部のコードがアプリケーションのごく一部に自然に制限されることがよくある場合でも、すべてのコードを同じヘッダーで定義する必要があります。
  4. 同じコードが2回割り当てられていないというチェックはありません
  5. のさまざまなフィールドを反復処理することはできませんenum

エラーコードソリューションを設計するとき、私は別の道を選びました。名前空間の定数で、ソースファイルで定義され、ポイント2と3に対応します。ただし、型の安全性を高めるために、定数はではなくint、特定のCodeクラスです。

namespace error { class Code; }

次に、いくつかのエラーファイルを定義できます。

// error/common.hpp

namespace error
{
  extern Code const Unknown;
  extern Code const LostDatabaseConnection;
  extern Code const LostNASConnection;
}

// error/service1.hpp
// error/service2.hpp

ただし、任意のキャストの問題は解決しませんでした(コンストラクターは明示的ですが公開されています)。私の場合、他のサーバーから返されたエラーコードを転送する必要があり、それらすべてを知りたくなかったためです(もろすぎたでしょう)

ただし、必要なコンストラクターをプライベートにし、ビルダーの使用を強制することで、4と5を一気に取得することもできます。

// error/code.hpp

namespace error
{
  class Code;

  template <size_t constant> Code const& Make(); // not defined here

  class Code: boost::totally_ordered<Code>
  {
  public:
    Code(): m(0) {} // Default Construction is useful, 0 is therefore invalid

    bool operator<(Code const& rhs) const { return m < rhs.m; }
    bool operator==(Code const& rhs) const { return m == rhs.m; }

  private:
    template <size_t> friend Code const& Make();
    explicit Code(size_t c): m(c) { assert(c && "Code - 0 means invalid"); }

    size_t m;
  };

  std::set<Code> const& Codes();
}


// error/privateheader.hpp (inaccessible to clients)

namespace error
{
  std::set<Code>& PrivateCodes() { static std::set<Code> Set; return Set; }

  std::set<Code> const& Codes() { return PrivateCodes(); }

  template <size_t constant>
  Code const& Make()
  {
    static std::pair< std::set<Code>::iterator, bool > r
      = PrivateCodes().insert(Code(constant));
    assert(r.second && "Make - same code redeclared");
    return *(r.first);
  }
}

//
// We use a macro trick to create a function whose name depends
// on the code therefore, if the same value is assigned twice, the
// linker should complain about two functions having the same name
// at the condition that both are located into the same namespace
//
#define MAKE_NEW_ERROR_CODE(name, value)         \
  Make<value>(); void _make_new_code_##value ();


// error/common.cpp

#include "error/common.hpp"

#include "privateheader.hpp"

namespace error
{
  Code const Unkown = MAKE_NEW_ERROR_CODE(1)
  /// ....
}

(フレームワークの場合)もう少し作業が必要で、同じ割り当てチェックのリンク時/実行時チェックのみです。パターンをスキャンするだけで重複を診断するのは簡単ですがMAKE_NEW_ERROR_CODE

楽しむ!

于 2010-09-17T21:31:48.780 に答える
0

覚えておくべきことの1つは、enum:のアドレスを取得できないことです。

const unsigned* my_arbitrary_item = &item_1_pos;

于 2010-09-17T19:44:41.893 に答える
0

それらが純粋に定数であり、実行時のものを必要としない場合(enum以外の値でenumを初期化できない場合など)、それらはconstunsignedintsである必要があります。もちろん、列挙型はタイピングが少ないですが、それは重要なことではありません。

于 2010-09-17T19:53:51.013 に答える
0

質問のタイトルは、列挙型の使用について疑問がある主な理由は、定数が非反復的であるということを示唆しています。しかし、C ++では、列挙型はすでに非反復型です。反復列挙型​​を作成するには、かなりの数のフープをジャンプする必要があります。

定数が本質的に関連している場合、定数が反復的であるかどうかに関係なく、列挙型はかなり良いアイデアだと思います。ただし、列挙型の主な欠点は、型制御がまったくないことです。多くの場合、定数値のタイプを厳密に制御することをお勧めします(符号なしにするなど)。これは、列挙型では(少なくともまだ)役に立たないことです。

于 2010-09-17T19:22:35.223 に答える