web-dev-qa-db-ja.com

「名前空間の使用」をヘッダーファイルに含めることがC ++で悪い考えであるのはなぜですか?

BruceEckelの「ThinkinginC++」から名前空間について読んでいるときに、次のステートメントに遭遇しました。

ただし、ヘッダーファイルにusingディレクティブが表示されることは事実上ありません(少なくともスコープ外ではありません)。その理由は、ディレクティブを使用すると、その特定の名前空間の保護がなくなり、その効果が現在のコンパイル単位の終わりまで続くためです。 usingディレクティブ(スコープ外)をヘッダーファイルに入れると、この「名前空間保護」の喪失が、このヘッダーを含むすべてのファイル内で発生することを意味します。これは、多くの場合、他のヘッダーファイルを意味します。

簡単な例を挙げて、上記のステートメントを理解するのを手伝っていただけませんか。

26
user388338

このプログラムを検討してください:

line#
    1 #include <string>                                                               
    2                                                                                 
    3 using namespace std;                                                            
    4                                                                                 
    5 struct string { const char* p; };  // Beware: another string!
    6                                                                                 
    7 int main()                                                                      
    8 {                                                                               
    9     string x; // Error: ambiguous - which string is wanted?
   10 }

コンパイルしようとすると、エラーが表示されます。

g++     using.cc   -o using
using.cc: In function `int main()':
using.cc:9: error: use of `string' is ambiguous
using.cc:5: error:   first declared as `struct string' here
/usr/lib/gcc/i386-redhat-linux/3.4.6/../../../../include/c++/3.4.6/bits/stringfwd.h:60: error:
   also declared as `typedef struct std::basic_string<char, std::char_traits<char>, std::allocator<char> > std::string' here
using.cc:9: error: `string' was not declared in this scope
using.cc:9: error: expected `;' before "x"

ここでの問題は、main()string x;を指定する場合、コンパイラーはユーザー定義の::stringまたは含まれるstd::stringが必要かどうかわからないことです。

ここで、プログラムの上部を取り、1行目から5行目までをstruct string ...まで取り、それをヘッダーファイルに入れて、main()の前に#includeするとします。何も変わりません。まだエラーがあります。したがって、スタンドアロンプ​​ログラムの場合と同様に、usingステートメントを含むヘッダーファイルは、それらを含む他のコードで問題を引き起こし、ステートメントの一部をあいまいにする可能性があります。

ただし、ヘッダーは、直接または間接的に、任意に大量の依存コードによって含めることができるため、より大きな問題になる可能性があります。

  • ヘッダーからusingステートメントを削除する、または
  • <string>の内容の変更、またはstd::に影響を与えるその他のヘッダー

...問題のあるヘッダーを含むコードが破損する可能性があります。どちらの問題も依存コードをコンパイルできなくする可能性があり、別のコンパイルが試行されるまで問題に気付かない可能性があります。さらに、usingステートメントが原因で苦しんでいる人は、ヘッダーからusingステートメントを削除したり、影響を受ける他のクライアントコードを修正したりするための、ファイルシステム/コードリポジトリのアクセス許可、企業権限などを持っていない可能性があります。

とはいえ、ヘッダーがクラスまたは関数内でのみ「使用」している場合、そのスコープを超えるコードには影響がないため、std ::への変更による潜在的な影響は大幅に軽減されます。

30
Tony Delroy

ヘッダーにusing namespace stdが含まれている場合、その名前空間のすべてが、ヘッダーを含むすべてのモジュールのグローバル名前空間に追加されます。

つまり、これらのモジュールのいずれのグローバル名前空間でも、関数を宣言したり、std関数/クラスと同じ名前(および関数の互換性のあるパラメーター)でクラスを定義したりすることはできません。

16
Fred Foo

「C++入門書、第5版」から次の段落をコピーします。

ヘッダー内のコードは通常、using宣言を使用しないでください。その理由は、ヘッダーの内容がインクルードプログラムのテキストにコピーされるためです。ヘッダーにusing宣言がある場合、そのヘッダーを含むすべてのプログラムは同じusing宣言を取得します。その結果、指定されたライブラリ名を使用することを意図していなかったプログラムで、予期しない名前の競合が発生する可能性があります。

5
Shen

さて、名前空間を使用する意味は何ですか。名前の衝突のリスクを回避するためです。

FooBarなど、かなり一般的なクラス名があるとします。複数のライブラリを使用する場合、ライブラリAのFooBarがライブラリBのFooBarと衝突するリスクがあります。そのために、2つの異なる名前名AとBを使用して、FooBarをグローバル名前付けからA :: FooBarとB :: FooBarに移動します。 (したがって、それらは互いに分離されています)。

次に、ヘッダーにusing A;using B;を入れると、A :: FooBarとB :: FooBarがFooBarだけに移動し、衝突が戻って、最初に名前空間を使用することによるメリットがなくなります。 。

4
Johan Kotlinski