web-dev-qa-db-ja.com

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

すべてのc ++コースで、すべての教師は常にusing namespace std;ファイルの#includesの直後に.hを配置します。これは、そのヘッダーを別のプログラムに含めることで、名前空間をプログラムにインポートするため、おそらく気づかず、意図せず、または欲しくないため、危険であると思われます(ヘッダーの包含は非常に深くネストできます)。

だから私の質問は二重です:using namespaceをヘッダーファイルで使用すべきではないこと、および/またはそれを元に戻す何らかの方法がありますか?

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

同じ行に沿ってもう1つ質問:ヘッダーファイル#includeに対応する.cppファイルに必要なすべてのヘッダー、ヘッダー定義に必要なヘッダーのみ、.cppファイルを#include、残りはなし、またはexternとして必要なすべてを宣言する必要があります?
質問の背後にある理由は上記と同じです。.hファイルを含めるとき、私は驚きを望みません。

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

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

110
Baruch

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

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

私はそれを一般的なものと呼ぶかどうかはわかりませんが、たまに否定的な結果を知らない新しいプログラマーによって書かれたものであることが時々明らかになります。通常、リスクを修正するのは比較的簡単なので、リスクについての少しの教育で問題を処理します。

105
Mark B

Sutter and Alexandrescuの項目59 「C++コーディング標準:101ルール、ガイドライン、およびベストプラクティス」

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

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

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

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

usingdeclarationは、1人のバディをもたらします。 usingdirectiveは、名前空間内のすべてのバディを取り込みます。教師によるusing namespace std;の使用はusingディレクティブです。

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

23
Andy Thomas

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

絶対に必要な場合(クラスの完全な定義が必要な場合)にのみヘッダー内にヘッダーを含め、どこでも(クラスが必要な場合はポインターまたは参照)前方宣言を使用する必要があります。

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

12
Mike O'Connor

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

GSFC C++コーディング標準には次のように書かれています。

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

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

6

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

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

5
Öö Tiib

「[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宣言がファイルスコープにある場合、これはヘッダーが含まれるファイルのスコープに拡張されます。

4
YoungJohn

プログラミングのすべてのものと同様に、プラグマティズムは独断主義、IMOに勝つはずです。

プロジェクト全体で決定を下す限り(「私たちのプロジェクトはSTLを広範囲に使用しており、すべてにstd ::。を追加する必要はありません」)、問題は見当たりません。リスクを抱えているのは名前の衝突だけです。結局のところ、STLが広く普及しているため、問題になることはほとんどありません。

一方、1つの(非プライベート)ヘッダーファイルで1人の開発者が決定した場合、チーム間で混乱が発生するため、回避する必要があります。

4
ijprest

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

4

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

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コンパイラでテストしました。

2