「名前空間を使用する」汚染とは何ですか?


15

私はグーグルコーディングガイドを見ていました[ここ]、彼らは私がそれを誤解しなかった場合、using namespaceまたはを使用することをお勧めしませんnamespace::function

これstdは同様に適用されますか?cout<<それなしでは機能しません。この本は、同じことをお勧めします。では、またはなしで使用するにはどうすれcout<<using namespace std;よいstd::cout<<ですか?

推奨される方法は何ですか?std::cout<<?ほとんどのC ++教科書using namespace std;は初心者向けに、コーディングの習慣が乏しいことを教えていますか?

回答:


18

Googleの標準を読むと、using namespace foo;どこでもディレクティブを使用できません。このディレクティブは、名前空間で宣言されたすべてを取り込み、衝突と予期しない動作の一般的な原因です。他の人は非常に一般的なものを引用しています:あなたはどこかに独自のmaxまたはminメソッドがあり、誰かがあなたのメソッドにヘッダーを含めてから言うsrcファイルで衝突しますusing namespace std;

特定の場所では、次の形式のusing宣言を使用できます。 using ::foo::bar;

タイピングの手間を省くため、コードにディレクティブを使用するのが好きですが、リスクが伴います。多くのcoutステートメントを含むファイルがある場合、std :: coutを100回入力する必要がないことは理解できますが、:: std :: coutを使用して単純に言うことができます。これらを変数宣言のように扱います。必要な場所にスコープを設定します。10のファイル内の1つの関数が出力を書き込む必要がある場合、先頭でcoutの方法を宣言せずに、実際の出力を行う関数にそれを配置します。

#include <ostream>
//using namespace std; // NO!
//using ::std::cout;   // less bad than using namespace, but I prefer to scope it

int main(int argc, char** argv)
{
   int rc = do_some_stuff(argc, argv);
   using ::std::endl;
   if (rc) { // print the success report
      using ::std::cout;
      cout << "The test run completed. The return code was " << rc << '.' << endl;
    } else {
      using ::std::cerr;
      cerr << "Unable to complete the test run." << endl;
    }
    return 0 == rc;
}

それはほんの数行で出力を行うという極端なものですが、アイデアは得られます。

もう1つできることは、入力を最小限に抑えるエイリアスまたはtypedefです。私はstd :: whateverが悪いとは思いませんが、数十個のモジュールを備えた膨大なソースセットがあり、時にはのようなコードを記述する必要がありますconsole_gui::command_window::append("text")。それはしばらくすると退屈になり、多くの長い行を引き起こします。私はすべてのようなものです

typedef console_gui::command_window cw;
cw::append("text");

エイリアスがローカルスコープで行われ、コードを読み取り可能にするのに十分なコンテキストを保持している限り。


1
ありがとう!これは本当に役に立ちます。良い例でなぜ悪いのかを説明しただけでなく、良い例で解決策を指摘しました。:-)
ロード・ロー。

1
ところで:使用std::endl上の明示的なフラッシュのためにstdout/ stderr通常は非常に不必要である、それらのストリームはに関連付けられていますstdout/ stderrとにかく。それは物事を少し遅くさえします。

8

これは、1)名前空間の目的全体を無効にし、名前の衝突を減らすことです。2)usingディレクティブで指定された名前空間全体をグローバル名前空間で利用できるようにします。

たとえば、独自のmax()関数を含めて定義すると、std :: max()と衝突します。

http://en.cppreference.com/w/cpp/algorithm/max

使用するネームスペースを明示的に指定するため、std :: member_you_wish_to_useを使用することをお勧めします。


これはstd::max()、名前空間のプレフィックスを使用する必要があることを意味します。または私は間違っていますか?
ローLord。

3
これは、「名前空間stdを使用」と入力すると、コード内で、独自のmax関数(またはstd名前空間で既に定義されている他の名前)を定義するとエラーが発生します
Chewy Gumball 14

1
usingこの場合、ディレクティブを定義して<algorithm>を含めた場合、max()関数が破損するため、ディレクティブに注意する必要があることを意味します。これは単純なケースですが、何が壊れるかわかりません。ライブラリ全体が壊れていないことを確認する必要がありますが、将来コードが壊れる(名前の衝突)かどうかはわかりません。
ApplePie 14

6

指定したリンクを引用:

.ccファイル内の任意の場所、および.hファイル内の関数、メソッド、またはクラスでusing宣言を使用できます。

// .ccファイルでOK。

// .hファイルの関数、メソッド、またはクラス内にある必要があります。

:: foo :: bar;を使用して

Googleスタイルでは、グローバルコンテキストでネームスペースをインポートすることは禁止されていますが、ローカルネームスペースでは許可されています。

宣言を使用すると、コードの限られた明確に見える部分にのみ影響を与えるすべての場所で、完全に受け入れられます。

グローバルコンテキストを汚染すると、無関係なコードが影響を受けます(ヘッダーを使用して暗黙的に)。ローカルコンテキストで実行しても何も起こりません。


同じ基準があります。一部の人々は、長い名前空間をローカルでtypedefします。例:typedef foolicious :: barlicious fb; fb :: drink d;
マイケルマシューズ14

1

彼らは、名前空間または名前空間:関数を使用することをお勧めしません-私がそれを誤解しなかった場合。

あなたがやった。推奨事項は、using namespaceディレクティブにのみ適用されます(これは一般的に、と呼ばれますがabusing namespace、完全にユーモラスではありません)。などの関数またはオブジェクトの完全修飾名を使用することを強くお勧めしますstd::cout


1

この質問にはすでに有用な答えがありますが、詳細の1つが短すぎるようです。

ほとんどのプログラマーは、宣言を参照して学習しようとしても、usingキーワードとnamespace使用法の説明と最初は少し混同されます。これは、宣言ディレクティブの読み取りが多少同等であるため、どちらもdで始まる比較的抽象的な長い単語です

名前空間内の識別子は、名前空間に明示的に名前を付けることでアクセスできます。

myNamespace::myIdent

これは、入力するキーがはるかに多い場合があります。ただし、ほとんどの識別子に同じ方法で接頭辞が付けられると、コードの重要性が低下する可能性もあります。usingキーワードは、これらの名前空間の欠点を防ぐことができます。以来using、コンパイラレベルでの作品(それはマクロません)、その効果は、それが中で使用されている全範囲のために持続します。Googleのスタイルが明確に定義されたスコープ、CPPファイルのヘッダファイルや関数内すなわちクラスにその使用を制限する理由だこと。

...もちろん、宣言の使用には違いがあります

using myNamespace::myIdent; // make myIdent an alias of myNamespace::myIdent

およびディレクティブ使用して

using myNamespace; // make all identifiers of myNamespace directly accessible

巨大なスコープで使用する場合は、後者のリードずっとより多くの混乱。


1

どうぞ:

#include <iostream>

int main()
{
    std::endl(std::operator<<(std::cout, "Hello world!"));
}

このように記述することで、ディレクティブや宣言の使用とともにエラーが発生しやすいADLを回避します。

これは皮肉な答えを意味します。:-D

これについては、Googleでハーブサッターと話します。C ++コーディング標準から:

あなたは、することができなければならない宣言使って名前空間を使用してディレクティブを #include指令とそれについての感じの良い後に実装ファイルに自由に。反対の主張が繰り返されるにもかかわらず、宣言とディレクティブを使用する名前空間は悪ではなく、名前空間の目的を無効にしません。むしろ、それらは名前空間を使用可能にするものです。

潜在的に名前空間の競合が発生する可能性がありますが、このような天文学的にまれなイベントでは、usingディレクティブを慎重に避け、using宣言で使用するすべてのもの(演算子まで)を明示的に指定することで、おそらく修正することは困難ではありませんただ先に進んでくださいusing namespace std。生産性の観点から後者をお勧めします。

ほとんどのC ++テキストブックは、初心者に名前空間stdの使用を教えています。彼らは貧しいコーディング慣行を伝播していますか?

あなたが私に尋ねた場合、反対は、私は上記のサッターが同意すると信じています。

現在、私のキャリアの中で、using数千万のLOCにわたるコードベースのディレクティブの直接的な結果として、合計で約3つの名前空間の競合に遭遇しました。ただし、3つすべてのケースで、それらは5万行を超えるレガシーコードにまたがるソースファイルにあり、元々はCで記述されてからC ++に加害され、多数の異なるライブラリのヘッダーを含む、さまざまな機能の膨大な折ec的なリストを実行し、#includesページにまたがる壮大なリスト。壮大な混乱にもかかわらず、ランタイムバグではなく、OSX(コードのビルドに失敗したOS)でビルドエラーを引き起こしたため、修正するのはそれほど難しくありませんでした。この悪夢のような方法でコードを整理しないでください。

ただし、ヘッダーファイルで usingディレクティブと宣言の両方を避けてください。それはただ遅らせただけです。ただし、ソースファイル、特に#includeディレクティブがページ全体に表示されていないファイルについては、Googleで作業していない場合でも汗をかかないでください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.