なぜ「ネームスペースstdを使用する」のですか?悪い習慣と考えていますか?


2640

私は書くことを他人に言われてきたusing namespace std;コードでは間違っている、と私は使うべきであるとstd::coutし、std::cin代わりに直接。

なぜusing namespace std;悪い習慣と見なされますか?非効率的ですか、あいまいな変数(std名前空間内の関数と同じ名前を共有する変数)を宣言するリスクがありますか?パフォーマンスに影響しますか?


512
「std :: cout;を使用して」できることを忘れないでください。つまり、std :: coutと入力する必要はありませんが、同時にstd名前空間全体を取り込む必要はありません。
ビル

2
@a有料オタクgoogle-styleguide.googlecode.com/svn/trunk/…リンクが機能しなくなりました。新しいリンクのようですgoogle.github.io/styleguide/cppguide.html#Other_C++_Features
MCG

64
ヘッダーファイルのファイルスコープで「using namespace std」を使用することは特に悪いことです。ソースファイル(* .cpp)の中でファイルスコープで使用した後、インクルードの効果は1つの翻訳単位に限定されるため、それほど悪くはありません。その効果は関数またはクラスのスコープに限定されるため、関数またはクラス内での使用は問題がさらに少なくなります。
sh- 2017年

5
私はディレクティブを使用して使用することを阻止するが、特定のような名前空間のだろうstd::literals::chrono_literalsPoco::Data:KeywordsPoco::Unitsおよびリテラルや可読性のトリックを扱いますもの。ヘッダーまたは実装ファイルにある場合は常に。関数のスコープでは問題ないかもしれませんが、リテラルやその他のものは別として、役に立ちません。
Ludovic Zenohate Lagouardette 2017

7
@ジョン:特に名前空間stdとは関係ありません。私が強調したのは、「ヘッダーファイルのファイルスコープ」です。アドバイスとして言えば、ヘッダーファイルのファイルスコープで「using namespace」(stdなど)を使用しないでください。実装ファイルで使用しても問題ありません。あいまいさでごめんなさい。
sh-

回答:


2230

これはパフォーマンスとはまったく関係ありません。しかし、これを考慮してください。FooとBarという2つのライブラリを使用しています。

using namespace foo;
using namespace bar;

すべてが正常に機能し、Blah()FooおよびQuux()Barから問題なく呼び出すことができます。しかし、ある日、Foo 2.0の新しいバージョンにアップグレードすると、Foo 2.0という関数が提供されQuux()ます。これで競合が発生しました。Foo2.0とBarの両方がQuux()グローバル名前空間にインポートされます。これは、特に関数パラメーターが偶然一致する場合は、修正するためにいくらかの努力が必要です。

foo::Blah()and を使用したbar::Quux()場合、の導入はfoo::Quux()イベントではありませんでした。


435
私は常にPythonの「big_honkin_nameをbhnとしてインポートする」が好きだったので、「big_honkin_name.something」ではなく「bhn.something」を使用できます。実際に入力を減らすことができます。C ++にはそのようなものがありますか?
paxdiablo 2009

764
@Pax名前空間io = boost :: filesystem;
AraK

152
それは「修正するためのいくらかの努力」であると言うことは過大評価していると思います。新しいfoo :: Quuxのインスタンスはないので、bar :: Quuxを使用して現在の使用をすべて明確にします。
MattyT 2009

289
賢明な人は、非修飾名がstdタイプと衝突するタイプのライブラリを作成しますか?
erikkallen 2009

94
@TomA:の問題#defineは、名前空間に限定されず、コードベース全体を踏みにじることです。名前空間のエイリアスが必要です。
sbi 2009

1391

グレッグが書いたすべてのことに同意します、追加したいと思います。グレッグが言ったよりもさらに悪化する可能性があります!

Library Foo 2.0 Quux()は、いくつかの呼び出しに対して、何年も前に呼び出されたコードQuux()よりも明確に一致する関数を導入できbar::Quux()ます。その後、コードは引き続きコンパイルされます、静かに間違った関数呼び出し、 god-knows-whatを実行します。それは物事が得ることができるのと同じくらい悪いです。

ことを覚えておいてくださいstd名前空間があり、その多く識別子のトンがある非常に一般的なもの(だと思うlistsortstringiteratorあまりにも、他のコードに表示される可能性が非常に高い、など)。

あなたがこれをありそうにないと考える場合:私がこの答えを出した約半年後、スタックオーバーフローで質問がありましstd::ここでは、このようなAの質問の他、より最近の例です。これは実際の問題です。


ここにもう1つデータポイントがあります。何年も前に、標準ライブラリのすべての接頭辞にを付ける必要があることを煩わしく思ったこともありましたstd::。それから私は、using関数スコープを除いてディレクティブと宣言の両方が禁止されることが最初に決定されたプロジェクトで働きました。何だと思う?私たちのほとんどは、プレフィックスの作成に慣れるまでに数週間を要し、さらに数週間後、ほとんどの人が実際にコードを読みやすくすることに同意しました。その理由は次のとおりです。文章を短くするか長くするかは主観的ですが、接頭辞は客観的にコードを明確にします。コンパイラーだけでなく、あなたも、どの識別子が参照されているかを簡単に確認できます。

10年の間に、そのプロジェクトは数百万行のコードを持つようになりました。これらの議論が何度も繰り返されるため、私はかつて(許可された)関数スコープがusing実際にプロジェクトで使用される頻度に興味を持っていました。私はそのソースをgrepしましたが、それが使用された場所は1ダースまたは20ダースしか見つかりませんでした。私にとってこれは、一度試してみると、std::使用が許可されている場所であっても、100 kLoCごとに一度でもディレクティブを使用するほど苦痛を感じないことを示しています。


結論:すべてに明示的にプレフィックスを付けることは、害を及ぼすことはなく、慣れがほとんどなく、客観的な利点があります。特に、コンパイラーと人間のリーダーによるコードの解釈を容易にします。これが、コードを書く際の主な目標になるはずです。


140
1行にまとめることができるコードの密度を著しく損ないます。結局、コードを非常に長い時間をかけて書きます。読みやすさが低下します。個人的には、短い(短すぎない)コードの方が読みやすい傾向にあると思います(読むものが少なく、気が散るのが少ないため)。
ライライアン

92
C ++に標準stringクラスができる前の昔は見逃していたと思います。すべてのライブラリに独自のクラスがあったようです。何を教えてください:コードはstd::で作成し続けるので、grep -v std:: | vim閲覧しているときにコードを実行できます。またはstd::、背景色と同じ色にするキーワードであるエディターを教えることができます。機能するものは何でも。
Mike DeSimone、

80
std::害はないと思います。これは非常に重要な情報(つまり、「後に来るものが標準ライブラリの一部」である)を含んでおり、それでもかなり短くてコンパクトなプレフィックスです。ほとんどの場合、まったく問題ありません。場合によっては、数行のコードがありますあなたは、特定のシンボルを参照する必要がある場所stdの名前空間をたくさんして、usingその特定の範囲内の文はうまく問題を解決します。しかし、一般的な場合には、それはノイズではありません、それは貴重な情報を伝達する。加えて、曖昧さを除去する。
jalf

147
私が見たときはいつでも、それについて考えるstd::必要がstd::ないからだと思います。私が表示された場合stringlist、またはmap自分自身で、私は少し疑問に思います。
Mateen Ulhaq、2011

68
そして、幸運が今まで何かを命名することなく、ジオメトリライブラリを書い@LieRyan vectortransformまたはdistance。そして、これらは標準ライブラリで使用されている多くの非常に一般的な名前の単なる例です。C ++の不可欠な部分である名前空間機能の恐怖や偏見からそれらを使用しないことを提案することは、むしろ逆効果です。
Christian Rau

420

using namespaceクラスのヘッダーファイルを配置する際の問題は、(ヘッダーファイルを含めることにより)クラスを使用したいすべてのユーザーが、他の名前空間も「使用」する(つまり、すべてを表示する)ことを強制することです。

ただし、(プライベート)* .cppファイルにusingステートメントを自由に配置できます。


このように「気軽に」と言うことに同意できない人がいることに注意してくださいusing。cppファイル内のステートメントはヘッダー内のステートメントより優れていますが(ヘッダーファイルをインクルードするユーザーには影響しないため)、それでもまだだとは思わないからです。良い(コードによっては、クラスの実装を維持することがより困難になる可能性があるため)。このC ++ Super-FAQエントリには、

usingディレクティブは、レガシーC ++コードとネームスペースへの移行を容易にするために存在しますが、少なくとも新しいC ++コードでは定期的に使用しないでください。

FAQは2つの代替案を提案しています。

  • 使用宣言:

    using std::cout; // a using-declaration lets you use cout without qualification
    cout << "Values:";
  • std ::と入力するだけ

    std::cout << "Values:";

1
もちろん、誰かがstd:cout << std :: hexを使って後でstd :: restore_cout_stateに失敗しないように、グローバルcoutの状態を想定するべきではありません。しかし、それはまったく別のファットバーグです。
MOZ

233

最近、Visual Studio 2010について不満を感じました。ほとんどすべてのソースファイルに次の2行が含まれていることがわかりました。

using namespace std;
using namespace boost;

多くのBoost機能がC ++ 0x標準に組み込まれ、Visual Studio 2010には多くのC ++ 0x機能があるため、突然これらのプログラムはコンパイルされませんでした。

したがって、回避using namespace X;は将来を見据えた形式の1つであり、使用中のライブラリーやヘッダーファイルへの変更を確実に行う方法は、プログラムを壊すことにはなりません。


14
この。Boostとstdは、特にC ++ 11以降、多くのオーバーラップがあります。
アインポクルム2016

1
私は一度それをして、難しい方法でレッスンを学びました。今usingでは、関数定義の外では決して使用せず、めったに使用using namespaceしません。
Ferruccio

210

ショートバージョン:usingヘッダーファイルでグローバル宣言またはディレクティブを使用しないでください。実装ファイルで自由に使用してください。ここでは何ハーブサッターアンドレイアレキは、この問題について言っているC ++コーディング規約(強調のために太字は私のものです):

概要

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

当然のこと:ヘッダーファイルでは、ディレクティブや宣言を使用して名前空間レベルを記述しないでください。代わりに、すべての名前を明示的に名前空間修飾します。(2番目のルールは最初のルールに従います。これは、ヘッダーが他のヘッダー#includeの後に表示される可能性があるものを認識できないためです。)

討論

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


4
ここでは、プログラマの意見より、私は言葉にすることを声明で100%に同意しながら、ひとつusingのヘッダに表示されることはありません、私は場所に無料のライセンスについては確信していないusing namespace xyz;場合は特に、あなたのコード内の任意の場所xyzですstdusing std::vector;名前空間から疑似グローバルスコープに単一の要素をプルするだけなので、衝突のリスクがはるかに少なくなるので、私はフォームを使用します。
dgnuff

2
@Orbitの@Lightness Racesには、もちろん、あなたの意見を受け入れる権利があります。この回答で与えられたアドバイスに同意しない理由を説明する試みがあった場合、さらに役立つでしょう。名前空間の「使用」が悪い場合に名前空間のポイントが何であるかを理解することは特に興味深いでしょうか?std :: coutの代わりにstd_coutだけで名前を付けないのはなぜですか。C++ /名前空間の作成者は、わざわざそれらを作成するときに何らかの考えを持っていたに違いありません。
nyholku 2016年

1
@nyholku:必要はありません-他の回答の大部分は、私がするのと同じ理由を与えます。また、コメントに追加した ":)"にも気を付けてください。名前空間が悪いとは言わなかった。
オービットでの軽さのレース

ええ、私はそれに気づきました:)しかし、IMOの回答の大部分(この賢人のアドバイスに反するもの)は誤った方向に進んでいます(私が現在大多数の統計を作成しているわけではありません)。名前空間が「悪くない」ことに同意した場合、この回答に同意しない場合、それらが適切であると考える場所を言うことができますか?
nyholku 2016年

私はそれusing namespaceが悪のように悪だと感じざるを得ませんgoto。どちらにも有効な使い方がありますが、1000回のうち999回は間違って使用されます。したがって、そうusing namespaceです、ソースでは、他のインクルードの名前空間をきちんと汚染しません。しかし、それはあなたが+ から発生する「楽しさ」(あなたが(暗黙のFoo::)を呼び出して)から突然保護することはなく、突然コードが(関連する変更なしで)破壊されます。マッチ(したがって、代わりに呼び出されるようになります)using namespace Foousing namespace Barbaz(xyz)Bar::baz()
CharonX

122

using特にヘッダーでは、グローバルスコープでディレクティブを使用しないでください。ただし、ヘッダーファイルでも適切な場合があります。

template <typename FloatType> inline
FloatType compute_something(FloatType x)
{
    using namespace std; // No problem since scope is limited
    return exp(x) * (sin(x) - cos(x * 2) + sin(x * 3) - cos(x * 4));
}

これは、明示的な修飾(std::sinstd::cos...)、短いため、ユーザー定義の浮動小数点型(引数依存ルックアップ(ADL)を使用)を操作できるためです。


9
申し訳ありませんが、これには強く同意しません。
Billy ONeal 2010

4
@Billy:userlib :: cos(userlib :: superint)の呼び出しをサポートする他の方法はありません。すべての機能に用途があります。
Zan Lynx

17
@ザン:もちろんあります。using std::cos;using std::sinなどの問題しかし、よく設計された任意の点であるuserlib彼らの持っているために起こっているsincos、自分の名前空間内だけでなく、ので、これは本当にあなたを助けていません。(using namespace userlibこの前にこのテンプレートがあり、それが同じくらい悪い場合をusing namespace std除き、その範囲は制限されていません。)さらに、私がこれまでに見たこのような唯一の機能はswapであり、そのような場合はテンプレートを作成することをお勧めしますstd::swap問題全体の専門化と回避。
Billy ONeal

11
@BillyONeal: template<typename T> void swap(MyContainer<T>&, MyContainer<T>&)(ない関数テンプレート部分的な特殊(FTPSは)ので、時にはあなたが代わりに過負荷をに頼る必要がある、ありません。
SBI

38
@BillyONeal:(7回賛成です!)コメントが間違っています。あなたが説明する状況は、ADLがカバーするように設計されたものとまったく同じです。簡単に言えば、あればx持っている1つ以上の「関連付けられた名前空間」(例えば、それはで定義されている場合namespace userlib)ルックスが好きなことを、その後の任意の関数呼び出しcos(x)ますさらに、これらの名前空間に見える- せずに任意のusing namespace userlib;必要は事前に。Zan Lynxは正しい(そしてC ++の名前の検索はビザンチンです...)
j_random_hacker

97

グローバルに使用しないでください

グローバル使用された場合のみ、「不良」と見なさます。なぜなら:

  • プログラミングしている名前空間が乱雑になります。
  • 多くのを使用すると、特定の識別子がどこから来ているのかを読者が理解するのが難しくなりますusing namespace xyz
  • ソースコードの他の読者に当てはまることは何でも、最も頻繁に読む読者、つまりあなた自身にさえ当てはまります。1、2年後に戻って見てください...
  • using namespace stdあなたが話しているだけでは、あなたがつかむものすべてに気づいていないかもしれません-そして、あなたが別のものを追加し#includeたり、新しいC ++リビジョンに移動したりすると、あなたは気づかなかった名前の衝突を得るかもしれません。

ローカルで使用できます

先に進んで、ローカルで(ほぼ)自由に使用してください。もちろん、これはあなたの繰り返しを防ぎますstd::-そして繰り返しも悪いです。

ローカルで使用するためのイディオム

C ++ 03ではswap、クラスの関数を実装するためのイディオム(定型コード)がありました。実際にローカルを使用することが提案されましたusing namespace std-または少なくともusing std::swap

class Thing {
    int    value_;
    Child  child_;
public:
    // ...
    friend void swap(Thing &a, Thing &b);
};
void swap(Thing &a, Thing &b) {
    using namespace std;      // make `std::swap` available
    // swap all members
    swap(a.value_, b.value_); // `std::stwap(int, int)`
    swap(a.child_, b.child_); // `swap(Child&,Child&)` or `std::swap(...)`
}

これは次の魔法を行います:

  • コンパイラはstd::swapfor value_、つまりを選択しますvoid std::swap(int, int)
  • オーバーロードをvoid swap(Child&, Child&)実装している場合、コンパイラはそれを選択します。
  • そのオーバーロードがない場合、コンパイラーはvoid std::swap(Child&,Child&)これらを使用して最善の交換を試みます。

C ++ 11では、このパターンを使用する理由はありません。の実装はstd::swap、潜在的な過負荷を見つけてそれを選択するように変更されました。


5
「std :: swapの実装は、潜在的な過負荷を見つけてそれを選択するように変更されました。」- 何?よろしいですか?swapそもそもカスタムを提供することは、C ++ 11ではそれほど重要ではないというのは事実ですが、std::swapそれ自体がより柔軟なため(移動セマンティクスを使用)です。しかし、std::swap自動的に独自のカスタムスワップを選択することは、私にとってはまったく新しいことです(そして、私はそれを本当に信じていません)。
Christian Rau

@ChristianRauそうだと思います。私はどこかでこれを読んだ。私たちはいつでもハワードに尋ねることができます、彼は知っているべきです。私は掘り掘り ...今
towi

14
スワップの場合でも、より明確な(そしてありがたいことにより一般的な)イディオムはusing std::swap;でなく書くことですusing namespace std;。より具体的なイディオムは副作用が少ないため、コードの保守が容易になります。
エイドリアン・マッカーシー

11
最後の文は間違っています。C ++ 11では、Std Swap Two Stepがを呼び出す正しい方法として正式に祝福さswapれ、標準の他のさまざまな場所が変更されて、swapそのように呼び出すようになりました(上記のようにNB using std::swapは正しい方法であり、ではありませんusing namespace std)。しかし、std::swapそれ自体は他のものを見つけてそれを使用するように強調されていませんでしswapた。std::swap呼び出された場合、std::swap使用されます。
ジョナサンウェイクリー2015

3
using std::swapローカル名前空間を減らし、同時に自己文書化コードを作成するために、ローカルで入力する方が賢明かもしれません。あなたはめったにので、ちょうど興味のある部品を取り出す、全体std名前空間に興味を持っていません。
ランディン

79

あなたは右のヘッダファイルをインポートする場合、あなたは突然のような名前持ってhexleftplusまたはcountあなたのグローバルスコープ内に。std::これらの名前が含まれていることに気付いていない場合、これは驚くべきことです。これらの名前をローカルで使用しようとすると、かなり混乱する可能性があります。

すべての標準的なものが独自の名前空間にある場合は、コードまたは他のライブラリとの名前の衝突を心配する必要はありません。


12
言うまでもなく+1 distance。それでも私は読みやすさを向上させるため、実際に可能な限り、修飾されていない名前を好む。加えて、私たちは通常、口頭のスピーチで物事を修飾せず、可能な曖昧さを解決することに時間を費やすことをいとわないという事実は、資格なしに話していることを理解し、ソースに適用できるという価値があることを意味しますコードは、資格がなくてもすべてが何であるかが明確になるように構造化されていることを意味します。
乾杯とhth。-Alf

ただし、公平に言うと、を含めない場合、それらのほとんどはありません<iomanip>。それでも、良い点。
einpoklum 2016

48

別の理由は驚きです。

私が見た場合cout << blahstd::cout << blah私が考える代わりに:これは何coutですか?それは正常coutですか?何か特別なものですか?


25
これは冗談ですか?本当にわからない。そうでなければ、私は個人的にはコードを信頼しない限り、それが通常の「カウト」であると思います。...そして、コードを信頼しない場合、なぜそもそもそれを使用するのですか?「Trust EvERYThING !!」ではないことに注意してください。しかし、たとえば、GitHubなどのよく知られたライブラリを扱っている場合、これは少しずれるように思えます。
ブレントリッテンハウス

28
@BrentRittenhouse coutは、誰もがそれを認識しているため、悪い例です。しかしfuture、金融アプリで想像してみてください。特定の日に何かを売買する契約ですか?いいえ、そうではありません。コードがstd::futureあなたをそれほど混乱させないだろうと言っていたら。
James Hollis

2
@BrentRittenhouseは少し悪い例かもしれません。少なくとも4つの異なるライブラリが存在します。「標準ライブラリですか?libstdc ++?stl?他に何か?」いいえ、誰もがstd :: coutを知っているわけではありません。少なくとも本質的に、私たちが受け取る7人の新しいワーカーのうち6人は知りません。教育のカリキュラムはそれらを教育に使用しないからです。私はprintfsを追い払わなければなりません。またはdebugs()-Qtから。
スウィフト-フライデーパイ

1
本当に?それは(挿入演算子の使用と)何がある場合は、C ++ですっごく多くの書籍の最初の章の最初の例では、かなりだだけ C ++いくつかの新しいBODSが知っています。
mckenzm

@mckenzm乱雑さを減らすために本や講義ノートに入れるかもしれませんが、コードには入れません
Martin Beckett

45

経験豊富なプログラマーは、問題を解決するものを何でも使用し、新しい問題を作成するものを回避し、この正確な理由により、ヘッダーファイルレベルのusingディレクティブを回避します。

また、経験豊富なプログラマーは、ソースファイル内の名前の完全修飾を避けようとします。これのマイナーな理由は、十分な理由がない限り、少ないコードで十分な場合に、より多くのコードを書くことはエレガントではないことです。これの主な理由は、引数依存検索(ADL)をオフにすることです。

これらの正当な理由は何ですかですか?プログラマーは明示的にADLをオフにしたい場合もあれば、明確化したい場合もあります。

したがって、以下は問題ありません。

  1. 関数の実装内の関数レベルのusingディレクティブとusing宣言
  2. ソースファイル内のソースファイルレベルのusing宣言
  3. (時々)ソースファイルレベルのusingディレクティブ

43

私はそれをグローバルに使用すべきではないことに同意しますが、のようにローカルで使用することはそれほど悪いことではありませんnamespace「C ++プログラミング言語」の例を次に示します

namespace My_lib {

    using namespace His_lib; // Everything from His_lib
    using namespace Her_lib; // Everything from Her_lib

    using His_lib::String; // Resolve potential clash in favor of His_lib
    using Her_lib::Vector; // Resolve potential clash in favor of Her_lib

}

この例では、構成から生じる潜在的な名前の衝突とあいまいさを解決しました。

そこで明示的に宣言された名前(のようなusing-declarationsによって宣言された名前を含むHis_lib::String)は、using-directive(using namespace Her_lib)によって別のスコープでアクセス可能にされた名前よりも優先されます。


29

それも悪い習慣だと思います。どうして?ある日、名前空間の機能はデータを分割することだと思ったので、すべてを1つのグローバルバッグに入れてそれを台無しにしてはいけません。

ただし、「cout」と「cin」を頻繁に使用する場合using std::cout; using std::cin;は、.cppファイルに次のように記述します(ヘッダーファイルには決して含まれません#include)。私は誰もストリームcoutやに名前を付けることは決してないと思いますcin。;)


7
これはローカルのusing 宣言であり、using ディレクティブとは大きく異なります。
sbi

25

コードを見て、それが何をするかを知るのは素晴らしいことです。見れば、それが図書館の流れstd::coutだとわかる。見ればわかりません。それは図書館の流れかもしれません。または、同じ関数で10行高い可能性があります。または次の名前の変数coutstdcoutcoutstdint cout = 0;staticcoutそのファイルでれ。それは何でもかまいません。

今度は100万行のコードベースを取得します。これはそれほど大きくはありませんが、バグを検索しています。つまり、この100万行には、本来の目的を果たさない1行があることを意味します。名前付きをcout << 1;読み取り、1ビット左にシフトして、結果を破棄できます。バグを探しているので、チェックする必要があります。私が本当に見たいと思っている方法を見ることができますか?static intcoutstd::cout

あなたが教師であり、生活のためにコードを書いたり維持したりする必要がなかった場合、これは本当に良い考えの一つです。私はコードを見るのが好きです(1)私はそれが何をするか知っています。そして、(2)それを書いている人はそれが何をするか知っていたと確信しています。


4
"std :: cout << 1"がstd名前空間のcoutという名前の静的intを読み取っていないことをどのようにして知っていますか?また、「<<」が何をするかをどうやって知るのですか;)??? ...この回答は、「使用」を回避するのに適したデータポイントではないようです。
nyholku 2015年

4
誰かがstd :: coutを整数に再定義した場合、あなたの問題は技術的ではなく社会的です-誰かがあなたのためにそれを持っています。(そして、おそらく#define true falseなどのすべてのヘッダーもチェックする必要があります)
Jeremy Friesner

2
coutを見ると、常にstd :: coutであることがわかります。私が間違っているのは、私ではなく、このコードを書いた人の問題です:)
Tien Do

22

それはすべて、複雑さを管理することです。名前空間を使用すると、必要のないものを取得するため、デバッグが困難になる可能性があります(おそらく私は言う)。std ::を使用すると、いたるところに読むのが難しくなります(より多くのテキストなど)。

コース用の馬-複雑さをどのようにして最高にできるか、そしてできると感じるかを管理します。


18

検討する

// myHeader.h
#include <sstream>
using namespace std;


// someoneElses.cpp/h
#include "myHeader.h"

class stringstream {  // Uh oh
};

これは簡単な例であることに注意してください。20個のインクルードとその他のインポートを含むファイルがある場合、問題を解明するために実行する依存関係がたくさんあります。さらに悪いことに、競合する定義によっては、他のモジュールで無関係なエラーが発生する可能性があります。

恐ろしいことではありませんが、ヘッダーファイルやグローバル名前空間で使用しないことで、頭痛の種を省くことができます。非常に限定されたスコープでそれを行うのはおそらく大丈夫ですが、関数がどこから来ているのかを明確にするために、余分な5文字を入力する問題に遭遇したことはありません。


18
  1. あなたとは異なるスタイルやベストプラクティスの意見を持つ人々によって書かれたコードを読むことができる必要があります。

  2. だけを使用している場合cout、混乱する人はいません。しかし、たくさんの名前空間が飛んでいて、このクラスが表示され、それが何をするのか正確にわからない場合、名前空間を明示的に指定すると、一種のコメントとして機能します。一見すると、「ああ、これはファイルシステムの操作です」または「ネットワークに関すること」です。


17

同時に多くの名前空間を使用することは明らかに惨事のレシピですが、再定義は自分のコードによってのみ発生する可能性があるため、JUST名前空間stdと名前空間のみを使用するstdことはそれほど大きな問題ではありません...

したがって、それらの関数を「int」や「class」などの予約名と見なしてください。

人々はそれについてそんなにアナルになるのをやめるべきです。あなたの先生はずっと正しかった。名前空間を1つだけ使用してください。それが、最初に名前空間を使用する重要なポイントです。同時に複数を使用することはできません。それがあなたのものでない限り。だから、再び、再定義は起こりません。


短い文字列好き-衝突を作成することは難しいが、ということはないminendlessして表示されstd::た名前空間。しかし、今でstd::は何千ものシンボルが含まれているので、読者が知らないかもしれない新しいシンボルがどこから来ているのかを知ることは読者にとって有用です。
Tom Swirly、2016年

std名前空間が存在するのは、あなた、同僚、または使用するミドルウェアを書く人々が、名前空間の内部に関数を配置することについて常に賢明であるとは限らないためです。したがって、たとえばstd :: minと他の誰かのレガシー:: min()がstdにあったときよりも前に衝突を起こしながら、すべてのstd ::をインポートできます。
エイケンドラム

14

ここでは他の人にも同意しますが、読みやすさに関する懸念に対処したいと思います。ファイル、関数、またはクラスの宣言の先頭でtypedefを使用するだけで、そのすべてを回避できます。

クラスのメソッドは同様のデータ型(メンバー)を扱う傾向があり、typedefはクラスのコンテキストで意味のある名前を割り当てる機会であるため、通常はクラス宣言で使用します。これは実際には、クラスメソッドの定義を読みやすくするのに役立ちます。

// Header
class File
{
   typedef std::vector<std::string> Lines;
   Lines ReadLines();
}

そして実装では:

// .cpp
Lines File::ReadLines()
{
    Lines lines;
    // Get them...
    return lines;
}

とは対照的に:

// .cpp
vector<string> File::ReadLines()
{
    vector<string> lines;
    // Get them...
    return lines;
}

または:

// .cpp
std::vector<std::string> File::ReadLines()
{
    std::vector<std::string> lines;
    // Get them...
    return lines;
}

ちょっとしたコメントですが、typedefは便利ですが、typedefを使用する代わりにLinesを表すクラスを作成することを検討します。
Eyal Solnik 2016年

14

懸念を明確にする具体例。2つのライブラリがfooありbar、それぞれに独自の名前空間があるという状況を想像してください。

namespace foo {
    void a(float) { /* Does something */ }
}

namespace bar {
    ...
}

次のように、自分のプログラムで一緒に使用するfoobarします。

using namespace foo;
using namespace bar;

void main() {
    a(42);
}

この時点で、すべてが正常です。プログラムを実行すると、「何かを実行」します。しかし、後で更新barして、次のように変更したとします。

namespace bar {
    void a(float) { /* Does something completely different */ }
}

この時点で、コンパイラエラーが発生します。

using namespace foo;
using namespace bar;

void main() {
    a(42);  // error: call to 'a' is ambiguous, should be foo::a(42)
}

したがって、「a」が意味することを明確にするために、メンテナンスを行う必要がありますfoo::a。これは望ましくありませんが、幸いにも非常に簡単です(コンパイラーがあいまいとしてマークfoo::するすべての呼び出しの前に追加するだけaです)。

しかし、代わりに次のように表示されるようにバーが変更された別のシナリオを想像してください。

namespace bar {
    void a(int) { /* Does something completely different */ }
}

この時点での呼び出しは、「何か」を実行a(42)するbar::a代わりに突然バインドfoo::aし、「まったく異なるもの」を実行します。コンパイラの警告などはありません。プログラムは、以前とはまったく異なる何かを黙って開始します。

名前空間を使用すると、このようなシナリオのリスクが発生します。そのため、名前空間の使用は不快です。名前空間に含まれるものが多ければ多いほど、競合のリスクが高くなるため、std(その名前空間に含まれるものの数が多いため)他の名前空間よりも名前空間の使用が不快になる可能性があります。

最終的には、これは書き込み可能性と信頼性/保守性の間のトレードオフです。読みやすさも考慮に入れるかもしれませんが、私はそれがどちらの方向に進んでいるかについての議論を見ることができました。通常、私は信頼性と保守性がより重要であると言いますが、この場合、かなりまれな信頼性/保守性への影響に対して常に書き込みコストを支払うことになります。「最良の」トレードオフは、プロジェクトと優先順位を決定します。


2番目のシナリオは、私にとって取り引きを締めくくります。再び名前空間はありません。そのような微妙な機能の変更を内部で検出されないようにすることはできません。
safe_malloc

13

名前空間は名前付きスコープです。名前空間は、関連する宣言をグループ化し、個別の項目を個別に保つために使用されます。たとえば、別々に開発された2つのライブラリが同じ名前を使用して異なるアイテムを参照する場合がありますが、ユーザーは両方を使用できます。

namespace Mylib{
    template<class T> class Stack{ /* ... */ };
    // ...
}

namespace Yourlib{
    class Stack{ /* ... */ };
    // ...
}

void f(int max) {
    Mylib::Stack<int> s1(max); // Use my stack
    Yourlib::Stack    s2(max); // Use your stack
    // ...
}

ネームスペース名を繰り返すと、リーダーとライターの両方にとって邪魔になることがあります。したがって、特定の名前空間からの名前は、明示的な修飾なしで使用できると述べることができます。例えば:

void f(int max) {
    using namespace Mylib; // Make names from Mylib accessible
    Stack<int> s1(max); // Use my stack
    Yourlib::Stack s2(max); // Use your stack
    // ...
}

名前空間は、さまざまなライブラリやさまざまなバージョンのコードを管理するための強力なツールを提供します。特に、非ローカル名への参照を明示的に作成する方法の選択肢をプログラマーに提供します。

出典: Bjarne StroustrupによるC ++プログラミング言語の概要


4
彼はC ++にこの機能を導入したときビャーネ・ストロヴストルップが獲得していることがない他の指導に基づいており、この答えは-2 ...少年Bjarneが悪いと、経験の浅いプログラマされていなければならないことは非常に興味深い
nyholku

@nyholku:これを見てください。
sbi

10

using namespace stdcountのあいまいさのためにがコンパイルエラーをスローする例。これは、アルゴリズムライブラリの関数でもあります。

#include <iostream>

using namespace std;

int count = 1;
int main() {
    cout << count << endl;
}

2
::count - 問題が解決しました。通常は、他の場所よりもstd名前空間の方が多くのものを使用します。
PSkocik 2015

ここでの本当の問題は、C ++にはまだ名前空間のないグローバルがあるということです。これと、「this」がメソッドに暗黙的に含まれているという事実により、適切な「count」変数を使用しても、数え切れないほど多くのバグと問題が発生します。;)
エイケンドラム

9

ソフトウェアやプロジェクトのパフォーマンスを悪化させることはありません。ソースコードの最初に名前空間を含めることは悪くありません。の包含using namespace std指示をかどうかは、ニーズと、ソフトウェアまたはプロジェクトの開発方法によって異なります。

namespace stdは、C ++標準関数と変数が含まれています。この名前空間は、C ++標準関数を頻繁に使用する場合に役立ちます。

このページで言及されているように

名前空間stdを使用するステートメントは、一般に悪い習慣と見なされています。このステートメントの代わりに、型を宣言するたびに、スコープoperator(::)を使用して、識別子が属する名前空間を指定することもできます。

そしてこの意見を見てください:

名前空間を多用し、何も衝突しないことを確認している場合、ソースファイルで「using namespace std」を使用しても問題はありません。

using namespace stdネームスペースからすべての関数と変数を呼び出すため、ソースファイルにを含めるのは悪い習慣だと言う人もいました。に含まれる別の関数と同じ名前で新しい関数を定義するnamespace std場合、関数をオーバーロードし、コンパイルまたは実行が原因で問題が発生する可能性があります。期待どおりにコンパイルまたは実行されません。

このページで言及されているように:

このステートメントにより、std ::を入力する手間が省けますが、std名前空間で定義されたクラスまたはタイプにアクセスするときはいつでも、std名前空間全体がプログラムの現在の名前空間にインポートされます。いくつかの例を挙げて、これがそれほど良いことではない理由を理解しましょう

...

開発の後の段階で、「foo」と呼ばれるライブラリにカスタム実装された別のバージョンのcoutを使用したいとします(たとえば)。

...

どのライブラリがcoutを指すのか、あいまいさがあることに注意してください。コンパイラはこれを検出し、プログラムをコンパイルしない場合があります。最悪の場合、識別子が属する名前空間を指定したことがないため、プログラムはコンパイルされても間違った関数を呼び出す可能性があります。


7

すべての条件下で必ずしも悪い習慣だとは思いませんが、使用する際には注意が必要です。ライブラリを作成している場合は、おそらく、名前空間とともにスコープ解決演算子を使用して、ライブラリが他のライブラリと頭をぶつけないようにする必要があります。アプリケーションレベルのコードについては、問題はありません。


7

「なぜ「ネームスペースstdを使用しているのか」。C ++で悪い習慣と見なされましたか?」

逆に言えば、なぜ余分な5文字を入力するのが面倒だと思われるのでしょうか。

たとえば、数値ソフトウェアを書くことを検討してください。"vector"が問題ドメインの最も重要な概念の1つであるのに、一般的な "std :: vector"を "vector"に削減してグローバル名前空間を汚染することを検討するのはなぜですか?


19
これは5文字だけではありません。標準ライブラリのオブジェクトタイプを参照するたびに、その5文字が追加されます。これは、標準ライブラリをよく使用している場合によく発生します。したがって、まともなサイズのプログラムでは、より現実的には数千文字の余分な文字になります。おそらく、 'using'ディレクティブが使用できるように言語に追加されました...
Jeremy Friesner

5
毎回5文字追加するのではなく、5文字です。おそらくマウスを数回クリックしてメニューをプルダウンし、選択したエディターで検索と置換を行います。
DaveWalley 2014年

1
読みやすさ。cout << hex << setw(4) << i << endl;より読みやすいstd::cout << std::hex << std::setw(4) << i << std::endl;
oz1cz 2014年

16
さらに悪いことに、にstd::map<std::string,std::pair<std::string,std::string>>比べてひどいmap<string,pair<string,string>>です。
oz1cz 2014年

4
とにかく、STDコンテナをtypedefしてstd ::にするのは良い習慣です。そしてC ++ 11はautoキーワードをもたらしました。これにより、例えばイテレータを使用する場合にさらに簡単になります。
juzzlin

7

私は他の人に同意します。名前の衝突、あいまいさを求めていますが、事実はそれほど明確ではありません。私は使用を見ることができますがusing、私の個人的な好みはそれを制限することです。他の人が指摘したことも強く考えます:

かなり一般的な名前である可能性がある関数名を検索したいが、std名前空間でのみ検索したい場合(またはその逆- 名前空間、名前空間、...にないすべての呼び出しを変更したい場合)、次に、これを行うにはどうすればよいですか?stdX

それを行うためのプログラムを書くこともできますが、プロジェクトを維持するためのプログラムを書くよりも、プロジェクト自体に時間を費やす方がいいのではないでしょうか。

個人的には、私は実際にはstd::プレフィックスを気にしません。私はそれを持たないよりも外観が好きです。それが明示的で「これは私のコードではない...私は標準ライブラリを使用している」と言っているのか、それ以外の何かであるかはわかりませんが、見た目は良いと思います。私が最近C ++を始めたばかりであることを考えると、これは奇妙かもしれません(Cと他の言語をずっと以前から使用していて、Cは、アセンブリのすぐ上で、私のお気に入りの言語です)。

上記のことや他の人が指摘していることと多少関係がありますが、もう1つあります。これは悪い習慣かもしれませんがstd::name、標準ライブラリのバージョンと名前をプログラム固有の実装用に予約することがあります。はい、確かにこれはあなたに噛みつき、一生懸命噛む可能性がありますが、すべて私がこのプロジェクトをゼロから始めたことに帰着し、私が唯一のプログラマーです。例:オーバーロードstd::stringして呼び出しますstring。役立つ追加があります。私がCとUnix(+ Linux)で小文字の名前を使用する傾向があったためです。

それ以外に、名前空間のエイリアスを持つことができます。以下は、言及されていない可能性のある有用な例です。私はC ++ 11標準、特にlibstdc ++を使用しています。まあ、それは完全なstd::regexサポートを持っていません。確かに、コンパイルはできますが、プログラマー側のエラーとして、例外をスローします。しかし、それは実装の欠如です。

だからここに私がそれを解決した方法があります。Boostの正規表現をインストールしてリンクします。次に、libstdc ++が完全に実装したときにこのブロックを削除するだけでコードが同じになるように、次のようにします。

namespace std
{
    using boost::regex;
    using boost::regex_error;
    using boost::regex_replace;
    using boost::regex_search;
    using boost::regex_match;
    using boost::smatch;
    namespace regex_constants = boost::regex_constants;
}

それが悪い考えであるかどうかについては議論しません。しかし私はそれがためにきれいに保つことを主張するだろう、私のプロジェクトと同時に、それは特定ます:確かに、私はブーストを使用する必要があります、しかし、私はのlibstdc ++最終的にそれを持っていますようにそれを使用しています。はい、独自のプロジェクトを開始し、最初から標準(...)で開始することは、メンテナンス、開発、およびプロジェクトに関連するすべてを支援するのに非常に役立ちます。

何かを明確にするためだけに:STLでクラスの名前を意図的に、より具体的に代わりに使用することは、実際には良い考えではないと思います。文字列は私にとっては例外です(最初の文字列、上、または2番目の文字列は無視してください。必要であればしゃれます)。私は「文字列」の概念が好きではなかったためです。

それでも、私はまだCに偏っていて、C ++に偏っています。詳細を節約すると、私が取り組んでいることのほとんどがCに適合します(しかし、それは良い練習であり、自分自身を作るための良い方法でした。閉鎖的ではなく、傲慢さが少なく、より受け入れやすくなっています。しかし、何がある便利なことは、一部が既に提案するものである:私は確かに私が何をした場合、名前が衝突する原因となる2名前を付けるためにソート(同じことを)(?それはかなり一般的で、それはない)リストを使用し、かusing namespace std;、などをそのために、私は具体的に制御することを好み、それを標準的な使用にするつもりなら、それを指定する必要があることを知っています。簡単に言えば、許可された仮定はありません。

Boostの正規表現をの一部にすることについても同様ですstd。私はこれを将来の統合のために行います-繰り返しますが、これは完全にバイアスであることを認めます-それは醜いほどではないと思いますboost::regex:: ...。確かに、それは私にとってもう1つのことです。C ++には、見た目やメソッドでまだ完全に受け入れるには至っていないことがたくさんあります(別の例:可変引数テンプレートとvar引数[可変引数テンプレートは非常に便利だと認めていますが])。私が受け入れるものでさえ、それは困難でした、そして、私はまだ彼らと問題を抱えています。


1
std名前空間の拡張は未定義の動作であるため、絶対に行わないでください。
タンブル

7

私の経験から言うと、たとえばを使用するライブラリが複数ある場合cout、別の目的で間違っcoutたを使用する可能性があります。

例えば、私が入力した場合、using namespace std;およびusing namespace otherlib;、ちょうど入力するcoutのではなく、(両方であることを起こるもの)std::cout(または'otherlib::cout')、あなたは間違ったものを使用して、エラーが発生する可能性があります。使用する方がはるかに効果的で効率的std::coutです。


6

修飾されていないインポートされた識別子では、識別子が宣言されている場所を見つけるためにgrepなどの外部検索ツールが必要です。これにより、プログラムの正確さについての推論が難しくなります。


6

それがどこにあるかによります。共通ヘッダーの場合は、グローバルネームスペースにマージすることにより、ネームスペースの値を減らしています。覚えておいてください、これはモジュールをグローバルにする素晴らしい方法かもしれません。


6

これは悪い習慣であり、グローバル名前空間汚染としてよく知られています。複数の名前空間がシグネチャ付きの同じ関数名を持っている場合、問題が発生する可能性があります。コンパイラーがどちらを呼び出すかを決定することは不明確であり、などの関数呼び出しで名前空間を指定している場合、これはすべて回避できますstd::cout。お役に立てれば。:)


5

あなたの質問に答えるために、私は実際にこのように見ています:多くのプログラマー(全員ではない)が名前空間stdを呼び出します。したがって、名前空間stdにあるものと同じ名前を衝突または使用するものを使用しないようにしてください。それはかなりのことですが、厳密に言えば考えられる一貫性のある単語や仮名の数に比べればそれほどではありません。

つまり、「これが存在することに依存しないでください」と言っているのは、存在しないことに依存するように設定しているだけです。あなたは常にコードスニペットを借りて、常にそれらを修復する問題を抱えています。ユーザー定義および借用したものを限られた範囲に維持し、グローバルとの関係を十分に保つようにします(正直に言うと、グローバルはほとんど常に「今すぐコンパイルして後で正常性を保つ」ための最後の手段です)。stdを使用すると「cout」と「std :: cout」の両方で機能するが、stdを使用しないと「std :: cout」でしか機能しないため、先生からのアドバイスは悪いと思います。すべての独自のコードを作成できるほど幸運であるとは限りません。

注:実際にコンパイラの動作について少し学ぶまでは、効率の問題にあまり重点を置かないでください。コーディングの経験が少しあれば、優れたコードを単純なものに一般化できる程度に気付く前に、それらについて多くを学ぶ必要はありません。すべてをCで記述した場合と同じくらい簡単です。優れたコードは必要以上に複雑ではありません。


有用な標準ライブラリー関数(<algorithm>たとえば、からの再発明)を知らない人がいくつもいることを考えると、同じ人々がそれらのIDを確実に回避できると想像するのは少し難しいようです。独自のコードを調べて、と呼ばれる変数や関数が存在しないことを教えてくださいcount。あるいはdistance、またはlogdestroylaunchvisitbetasamplemessagesclamperasecopymodulusleft、などではない、まだすべての識別子は言うまでもありませんstdそのC ++ 35が...出て来るとき、あなたのコードが壊れます
トビースパイツ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.