C ++ヘッダーでの「名前空間の使用」


119

すべてのc ++コースでは、すべての教師が常にsのusing namespace std;直後にファイルを配置#includeしてい.hます。そのヘッダーを別のプログラムに含めることにより、おそらくそれを実現、意図、または希望せずに名前空間をプログラムにインポートすることになるので、これは危険に思えます(ヘッダーの組み込みは非常に深くネストされる可能性があります)。

だから私の質問は二重です:using namespaceヘッダーファイルで使用してはいけないことは正しいのでしょうか?

//header.h
using namespace std {
.
.
.
}

同じラインに沿ってもう一つ質問:万一のヘッダーファイル#includeすべてのヘッダーそれが対応だと.cppファイルのニーズを、のみヘッダー定義のために必要であるとしましょう.cppファイル#include休息、またはそれとして必要なしと宣言すべてをextern
質問の背後にある理由は上記と同じ.hです。

また、私が正しい場合、これはよくある間違いですか?実際のプログラミングとそこにある「実際の」プロジェクトのことです。

ありがとうございました。



3
補足として、using namespaceステートメントが原因で名前の衝突が発生した場合は、完全修飾名を使用して問題を解決できます。
Marius Bancila、2011年

回答:


115

using namespace正確に言うと、ヘッダーを含む他のファイルのコードの意味が予期せず変更される可能性があるため、ヘッダーでは絶対に使用しないでください。これを元に戻す方法はありませんusing namespace。これは非常に危険なもう1つの理由です。私は通常grepusing namespaceより複雑なことをするのではなく、ヘッダーなどで呼び出されていないことを確認するためになどを使用します。おそらく静的コードチェッカーもこれにフラグを立てます。

ヘッダーには、コンパイルする必要があるヘッダーのみを含める必要があります。これを強制する簡単な方法は、最初に、各ソースファイルの独自のヘッダーを常に他のヘッダーの前に含めることです。ヘッダーが自己完結していない場合、ソースファイルはコンパイルに失敗します。ライブラリ内の実装詳細クラスを参照する場合など、場合によっては、#includeそのような前方宣言されたクラスの定義を完全に制御できるため、代わりに前方宣言を使用できます。

私はそれを一般的に呼ぶかどうかはわかりませんが、それは時々間違いなく時々間違いなく現れますが、通常、悪影響を認識していない新しいプログラマーによって書かれます。修正は比較的簡単であるため、通常、リスクについての少しの教育ですべての問題に対処します。


2
ファイルでusingステートメントを自由に使用.cppできますか?3rdPartyLib::BigClassName<3rdPartyLib::AnotherBigName,3rdPartyLib::AnotherBigName>::Iteratorsが指先に死亡しています。
クリストファー

1
templateヘッダーにあるはずの関数をどのように合理化すればよいですか typedefs
クリストファー

1
@donlan、しばらくの間応答がないようです...はい、スコープはそのファイルのみに制限されるため、ファイルusing内のステートメントは.cppそれほど心配することなく使用できますが、#includeステートメントの前には実行しないでください。ヘッダーで定義されたテンプレート関数については、残念ながら名前空間を書き出す以外に適切な解決策がわかりません...おそらく、using宣言を別のスコープ内に配置して、{ /* using statement in between brackets */ }少なくとも現在のファイルをエスケープできないようにすることができます。
tjwrona1992

26

SutterおよびAlexandrescuの「C ++ Coding Standards:101 Rules、Guidelines、and Best Practices」の 59項:

59.ヘッダーファイル内または#includeの前に名前空間を使用しないでください。

名前空間usingは便宜上のものであり、他人に与えるものではありません。using宣言のusing前に#includeディレクティブやディレクティブを記述しないでください。

結果:ヘッダーファイルでは、名前空間レベルのusingディレクティブやusing宣言を記述しないでください。代わりに、明示的にすべての名前を名前空間で修飾します。

ヘッダーファイルは、1つ以上のソースファイルのゲストです。usingディレクティブと宣言を含むヘッダーファイルには、乱暴な仲間も含まれています。

using 宣言は 1つのバディにもたらします。using ディレクティブは、名前空間内のすべての仲間にもたらします。あなたの教師の使用using namespace std;はusingディレクティブです。

もっと真剣に、私たちは名前の衝突を避けるために名前空間を持っています。ヘッダーファイルは、インターフェイスを提供するためのものです。ほとんどのヘッダーは、現在または将来、どのコードに含まれる可能性があるかを認識していません。usingヘッダー内の内部の便宜のためにステートメントを追加すると、そのヘッダーのすべての潜在的なクライアントにそれらの便利な名前が付けられます。それは名前の衝突につながる可能性があります。そしてそれはただの失礼です。


12

ヘッダー内にヘッダーを含める場合は注意が必要です。大規模なプロジェクトでは、非常に絡み合った依存関係チェーンが作成され、実際に必要なものよりも大きい/長い再構築がトリガーされます。この記事そのフォローアップをチェックして、C ++プロジェクトにおける適切な物理構造の重要性について詳しく学んでください。

絶対に必要な場合(クラスの完全な定義が必要な場合)にのみヘッダー内にヘッダーを含め、可能な限り前方宣言を使用してください(クラスが必要な場合はポインターまたは参照です)。

名前空間については、ヘッダーファイルで明示的な名前空間スコープを使用する傾向がありusing namespace、cppファイルにのみ配置します。


1
template関数宣言をどのように効率化しますか?ヘッダーで発生する必要がありますか?
クリストファー

6

Goddard Space Flight Centerコーディング標準(CおよびC ++用)を確認してください。それは以前よりも少し難しいことがわかります-SOの質問に対する更新された回答を参照してください:

GSFC C ++コーディング標準によると、

§3.3.7各ヘッダーファイルは#include、ユーザーに#include必要なファイルを強制するのではなく、コンパイルする必要のあるファイルでなければなりません。#includesヘッダーが必要とするものに制限されます。その他#includesはソースファイルに配置する必要があります。

相互参照された最初の質問には、GSFC Cコーディング標準からの引用と根拠が含まれていますが、実質は同じです。


5

using namespaceヘッダー内が危険なのはあなたの言う通りです。元に戻す方法がわかりません。検出は簡単ですが、検索するだけですusing namespaceヘッダーファイルをできます。その最後の理由のため、実際のプロジェクトでは一般的ではありません。より経験豊富な同僚は、誰かがそのようなことをするとすぐに不平を言うでしょう。

実際のプロジェクトでは、インクルードするファイルが少ないほどコンパイルが高速になるため、インクルードされるファイルの量を最小限に抑えようとします。それは皆の時間を節約します。ただし、ヘッダーファイルの前に何かを含める必要があると想定している場合は、ヘッダーファイル自体も含める必要があります。それ以外の場合は、ヘッダーが自己完結しません。


4

あなたが正しいです。また、どのファイルにも、そのファイルに必要なヘッダーのみを含める必要があります。「現実世界のプロジェクトでは、よくあることは間違っていますか?」-ああ、そう!


4

プログラミングにおけるすべてのものと同様に、実用主義は独断主義、IMOに勝つはずです。

プロジェクト全体で決定を下す限り(「私たちのプロジェクトはSTLを広範囲に使用しており、すべてにstd ::。を前に付ける必要はありません。」)、それに関する問題はありません。あなたが危険を冒している唯一のものは、結局のところ、名前の衝突であり、STLの遍在性があれば、問題になる可能性はほとんどありません。

一方、1人の開発者が単一の(非公開ではない)ヘッダーファイルで決定した場合は、チーム間で混乱が生じ、回避する必要があることがわかります。


4

「元に戻す方法はありますか[a using宣言]ますか?」について

using宣言はスコープの影響を受けることを指摘しておくと役に立ちます。

#include <vector>

{   // begin a new scope with {
    using namespace std;
    vector myVector;  // std::vector is used
}   // end the scope with }

vector myOtherVector;   // error vector undefined
std::vector mySTDVector // no error std::vector is fully qualified

そう効果的にはい。の範囲を制限することによりusing宣言その効果はそのスコープ内でのみ持続します。そのスコープが終了すると、「取り消されます」。

using宣言が他のスコープ外のファイルで宣言されている場合、宣言にはファイルスコープがあり、そのファイル内のすべてに影響します。

ヘッダーファイルの場合、using宣言がfile-scopeにあると、ヘッダーが含まれるすべてのファイルのスコープに拡張されます。


2
あなたは実際の質問を理解した唯一の人のようです...しかし、私のコンパイルはクラスの減速の中で使用することについて私はあまり満足していません。
rustypaper 2017年

この答えは、スコープがどのように機能するか(namespace宣言など)と、OPが実際にどのように機能するか(変数のように)のOPの考え方の問題を説明することでさらに改善できます。 {}それを含むことは{}、それに関連することを何も行っていない後、そのスコープを制限します。これは、using namespaceがグローバルに適用される偶発的な方法です。
TafT 2018年

2

次のようにネストされた名前空間で宣言を記述すれば、C ++ヘッダーで「using」を安全に使用できると思います。

namespace DECLARATIONS_WITH_NAMESPACES_USED_INCLUDED
{
    /*using statements*/

    namespace DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED
    {
        /*declarations*/
    }
}

using namespace DECLARATIONS_WITH_NAMESPACES_USED_INCLUDED::DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED;

これには、名前空間を使用せずに、「DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED」で宣言されたもののみを含める必要があります。mingw64コンパイラでテストしました。


これは私が今まで見たことのない便利なテクニックです。ありがとう。通常、私は完全なスコープ修飾を使用し、using関数定義の内部に宣言を配置して、それらが関数の外部で名前空間を汚染しないようにしてきました。しかし、ヘッダーファイルでC ++ 11ユーザー定義リテラルを使用したいと思います。通常の規則に従って、リテラル演算子は名前空間によって保護されています。しかし、非汚染using宣言を使用できるスコープにないコンストラクター初期化子リストでそれらを使用したくありません。したがって、これはその問題を解決するのに最適です。
Anthony Hall

このパターンの残念な副作用は、最も内側の名前空間内で宣言されたクラスが、完全修飾名:でコンパイラエラーメッセージに表示されることですerror: ... DECLARATIONS_WITH_NAMESPACES_USED_INCLUDED:: DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED::ClassName ...。少なくとも、それは私にとってg ++で起こっていることです。
Anthony Hall
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.