c++ - 名前のない名前空間を使用する理由とその利点は何ですか?


私はちょうど新しいC ++ソフトウェアプロジェクトに参加しました。私はそのデザインを理解しようとしています。 このプロジェクトは名前のない名前空間を頻繁に使用します。 たとえば、次のようなものがクラス定義ファイルで発生する可能性があります。

// newusertype.cc
namespace {
  const int SIZE_OF_ARRAY_X;
  const int SIZE_OF_ARRAY_Y;
  bool getState(userType*,otherUserType*);
}

newusertype::newusertype(...) {...

名前のない名前空間を使用する可能性のある設計上の考慮事項は何ですか? 利点と欠点は何ですか?




Answers


(以下では、 ストライクスルーはC ++ 11にも当てはまらないものですが、C ++ 03にも当てはまりました。C ++ 11ではこれ以上ほとんど違いはありません私が思い出すことのできない弁護士の違い)。

無名名前空間は、識別子を効率的に翻訳単位にするためのユーティリティです。 名前空間の変換単位ごとに一意の名前を選択するかのように動作します。

namespace unique { /* empty */ }
using namespace unique;
namespace unique { /* namespace body. stuff in here */ }

空の本体を使用する余分なステップが重要なので、すでにusingディレクティブが使用されているので、名前空間本体内でその名前空間で定義されている::nameなどの識別子を参照できます。

つまり、複数の翻訳単位に存在する可能性のある(たとえば) helpなどの自由な機能を持つことができ、リンク時には一意の名前空間を持つので 、リンク時に衝突しません。 この効果は、Cで使用されている識別子の宣言に使用できるstaticキーワードを使用する場合とほとんど同じです。 そのような方法で使用されるstaticは、名前のない名前空間が型変換単位をローカルにすることもできる優れた選択肢であるため、C ++では非推奨です

namespace { int a1; }
static int a2;

どちらも翻訳単位であり、リンク時には衝突しません。 しかし、違いは、匿名の名前空間のa1が一意の名前を取得するということです。 依然として外部リンケージがあり、作成中のオブジェクトファイルのシンボルテーブルにエクスポートすることができます。 これはテンプレートの引数としてアドレスを使用する場合に重要になります。

template<int * ptr> struct sample { };

// OK - a1 has external linkage
sample<&a1> s1; 
// NOT OK - translation unit locality is done by giving a2 internal linkage. 
sample<&a2> s2; 

テンプレートパラメータには外部リンケージが必要です。この場合、識別子は匿名名前空間に入れなければなりません。

comauコンピューティングの優れた記事を読んでください。なぜ静的ではなく無名の名前空間が使われていますか?




匿名の名前空間に何かがあるということは、この翻訳単位 (.cppファイルとそのすべてのインクルード)にローカルであることを意味します。つまり、同じ名前を持つ別のシンボルが他の場所で定義されている場合、ODR( One Definition Rule )に違反しません。

これは、静的なグローバル変数または静的関数を持つCの方法と同じですが、クラス定義にも使用できます(C ++でstaticではなく使用する必要があります)。

同じファイル内のすべての匿名名前空間は同じ名前空間として扱われ、異なるファイル内のすべての匿名名前空間は区別されます。 匿名の名前空間は、次のものと同じです。

namespace __unique_compiler_generated_identifer0x42 {
    ...
}
using namespace __unique_compiler_generated_identifer0x42;



この例では、参加したプロジェクトのメンバーが匿名の名前空間を理解できないことを示しています:)

namespace {
    const int SIZE_OF_ARRAY_X;
    const int SIZE_OF_ARRAY_Y;

constオブジェクトはすでに静的なリンケージを持っているため、別の翻訳単位の同じ名前の識別子と競合する可能性はないため、これらは匿名の名前空間にある必要はありません。

    bool getState(userType*,otherUserType*);
}

これは実際には悲観的ですgetState()は外部リンケージがあります。 静的リンケージはシンボルテーブルを汚染しないので、通常は静的リンケージを使用することをお勧めします。 それは書く方が良い

static bool getState(/*...*/);

ここに。 私は同じトラップに陥っています(標準では、ファイル名は匿名の名前空間の代わりに何らかの理由で廃止されていることを示唆しています)が、KDEのような大規模なC ++プロジェクトでは、頭を適切に回す人がたくさんいますもう一度:)




この質問に対する他の回答に加えて、匿名の名前空間を使用すると、パフォーマンスが向上する可能性があります。 名前空間内のシンボルは外部リンケージを必要としないため、コンパイラは名前空間内のコードを積極的に最適化することができます。 例えば、ループ内で複数回呼び出される関数は、コードサイズに影響を与えずにインライン化することができます。

例えば、私のシステムでは、匿名の名前空間が使用されている場合(x86-64 gcc-4.6.3と-O2; add_valの余分なコードはコンパイラにそれは2回)。

#include <iostream>

namespace {
  double a;
  void b(double x)
  {
    a -= x;
  }
  void add_val(double x)
  {
    a += x;
    if(x==0.01) b(0);
    if(x==0.02) b(0.6);
    if(x==0.03) b(-0.1);
    if(x==0.04) b(0.4);
  }
}

int main()
{
  a = 0;
  for(int i=0; i<1000000000; ++i)
    {
      add_val(i*1e-10);
    }
  std::cout << a << '\n';
  return 0;
}



匿名の名前空間は、囲まれた変数、関数、クラスなどをそのファイル内でのみ使用可能にします。 あなたの例では、グローバル変数を避ける方法です。 実行時またはコンパイル時のパフォーマンスの違いはありません。

「この変数、関数、クラスなどを公開してもプライベートにしたいのですか?」以外のメリットとデメリットはあまりありません。




無名の名前空間は、クラス、変数、関数、オブジェクトへのアクセスを、それが定義されているファイルに限定します。 名前空間の無しの機能は、C / C ++のstaticキーワードに似ていstatic
staticキーワードは、グローバル変数と関数が定義されているファイルへのアクセスを制限します。
名前のない名前空間とstaticキーワードの間には違いがあります。名前のない名前空間は静的なものよりも利点があります。 staticキーワードは、変数、関数、オブジェクトで使用できますが、ユーザー定義クラスでは使用できません。
例えば:

static int x;  // Correct 

しかし、

static class xyz {/*Body of class*/} //Wrong
static structure {/*Body of structure*/} //Wrong

しかし、名前のない名前空間でも同じことが可能です。 例えば、

 namespace {
           class xyz {/*Body of class*/}
           static structure {/*Body of structure*/}
  } //Correct