Google C++ スタイル ガイドの名前空間セクションには、「ヘッダー ファイルで名前のない名前空間を使用すると、C++ One Definition Rule (ODR) に違反する可能性があります」と記載されています。
実装ファイルで名前のない名前空間を使用しないと ODR 違反が発生する理由は理解できますが、ヘッダーで使用するとどのように発生するかはわかりません。これがどのように違反を引き起こす可能性がありますか?
Google C++ スタイル ガイドの名前空間セクションには、「ヘッダー ファイルで名前のない名前空間を使用すると、C++ One Definition Rule (ODR) に違反する可能性があります」と記載されています。
実装ファイルで名前のない名前空間を使用しないと ODR 違反が発生する理由は理解できますが、ヘッダーで使用するとどのように発生するかはわかりません。これがどのように違反を引き起こす可能性がありますか?
その理由は、匿名の名前空間で実際に何かを使用すると、未定義の動作が発生するリスクがあるためです。例えば:
namespace {
double const pi = 3.14159;
}
inline double twoPiR( double r ) { return 2.0 * pi * r; }
インライン関数 (およびクラス、テンプレート、および複数の翻訳単位で定義する必要があるその他のもの) の規則は、トークンが同一でなければならず (マクロをヒットしない限り、通常はそうです)、すべてのシンボルが同一にバインドされなければならないということです。 . この場合、各翻訳単位には の個別のインスタンスがpi
あるため、pi
intwoPiR
は各翻訳単位の異なるエンティティにバインドされます。(いくつかの例外がありますが、それらはすべて整数式を含みます。)
もちろん、匿名の名前空間がなくても、ここでは未定義の動作になります (const
既定では内部リンケージを意味するため) が、基本原則は保持されます。名前のない名前空間 (またはヘッダーで定義された任意の const オブジェクト) 内の何かをヘッダーで使用すると、未定義の動作が発生する可能性があります。それが実際の問題であるかどうかによって異なりますがpi
、上記の のアドレスに実際に関係するものはすべて問題を引き起こします。(ここで「本当に」と言ったのは、アドレスや参照が正式に使用される場合が多いためですが、実際には、インライン展開すると、実際に使用される値になります。もちろん、トークン3.14159
は3.14159
どこにでもあります。が表示されます。)
test.h で
namespace {
int x;
}
namespace{
int x;
}
そのヘッダー ファイルを任意のソース ファイルに含めると、ODR 違反が発生します。これは、x
が 2 回定義されているためです。これは、コンパイラによって名前のない名前空間に一意の識別子が与えられ、翻訳単位内の名前のない名前空間のすべての出現箇所に同じ識別子が与えられるために発生します。言い換えると、すべての TU には名前のない名前空間が 1 つしかありません。