「名前空間stdを使用する」のはなぜですか。悪い習慣だと思いますか?
using namespace std;
コードを書くのは間違っているので、代わりに直接使用する必要があるstd::cout
と他の人から言われましたstd::cin
。
なぜusing namespace std;
悪い習慣と見なされるのですか?それは非効率的ですか、それともあいまいな変数(std
名前空間の関数と同じ名前を共有する変数)を宣言するリスクがありますか?パフォーマンスに影響しますか?
回答
これはパフォーマンスとはまったく関係ありません。ただし、これを考慮してください。FooとBarという2つのライブラリを使用しています。
using namespace foo;
using namespace bar;
すべてが正常に機能し、Blah()
FooおよびQuux()
Barから問題なく電話をかけることができます。しかし、ある日、Foo 2.0の新しいバージョンにアップグレードすると、Quux()
。という機能が提供されるようになります。これで競合が発生しました。Foo2.0とBarの両方がQuux()
グローバル名前空間にインポートされます。これは、特に関数のパラメーターがたまたま一致する場合、修正するのにいくらかの努力が必要になります。
とを使用foo::Blah()
していた場合bar::Quux()
、の導入はfoo::Quux()
イベントではなかったでしょう。
グレッグが書いたすべてに同意しますが、付け加えたいと思います。グレッグが言ったよりもさらに悪化する可能性があります。
Library Foo 2.0Quux()
は、何年にもわたって呼び出されたコードQuux()
よりも、いくつかの呼び出しに明確に一致する関数を導入する可能性がありますbar::Quux()
。次に、あなたのコードはまだコンパイルしますが、それは静かに間違った関数を呼び出すと、神が、知っている-何を行います。それは物事が得ることができるのと同じくらい悪いです。
ことを覚えておいてくださいstd
名前空間があり、その多く識別子のトンがある非常に一般的なもの(だと思うlist
、sort
、string
、iterator
あまりにも、他のコードに表示される可能性が非常に高い、など)。
これがありそうもないと思うなら:私がこの答えを出した約半年後に、これがほぼ正確に起こった(プレフィックスが省略されたために間違った関数が呼び出された)という質問がStackOverflowでここに尋ねられましたstd::
。これは、そのような質問のもう1つの最近の例です。ですから、これは本当の問題です。
もう1つのデータポイントは次のとおりです。何年も前、私は標準ライブラリのすべてにstd::
。をプレフィックスとして付ける必要があるのも面倒だと思っていました。それから私は、using
関数スコープを除いてディレクティブと宣言の両方が禁止されることが最初に決定されたプロジェクトで働きました。何だと思う?私たちのほとんどは、プレフィックスの記述に慣れるのに非常に数週間かかり、さらに数週間後、実際にコードが読みやすくなることに同意しました。それには理由があります。短い散文と長い散文のどちらが好きかは主観的ですが、接頭辞は客観的にコードを明確にします。コンパイラだけでなく、あなたも、どの識別子が参照されているかを簡単に確認できます。
10年で、そのプロジェクトは数百万行のコードを持つようになりました。これらの議論が何度も出てくるので、私はかつて、(許可された)関数スコープがusing
実際にプロジェクトでどのくらいの頻度で使用されているのか興味がありました。私はそれのソースをgrepしましたが、それが使用された場所は1つか2ダースしか見つかりませんでした。私にとってこれは、一度試してみると、std::
使用が許可されている場合でも、100kLoCごとに1回でもディレクティブの使用を採用するほど苦痛を感じないことを示しています。
結論:すべてを明示的に接頭辞として付けることは害を及ぼすことはなく、慣れるのにほとんど時間がかからず、客観的な利点があります。特に、コンパイラーと人間の読者がコードを解釈しやすくします。これが、コードを作成する際の主な目標になるはずです。
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:";
短いバージョン:using
ヘッダーファイルでグローバル宣言またはディレクティブを使用しないでください。実装ファイルで自由に使用してください。ここでは何ハーブサッターとアンドレイアレキは、この問題について言っているC ++コーディング規約(強調のために太字は私のものです):
概要
名前空間の使用は、他の人に与えることではなく、ユーザーの便宜のためです。#includeディレクティブの前にusing宣言またはusingディレクティブを記述しないでください。
当然の結果:ヘッダーファイルでは、ディレクティブや宣言を使用して名前空間レベルを記述しないでください。代わりに、すべての名前を明示的に名前空間で修飾します。(2番目のルールは最初のルールに従います。ヘッダーは他のヘッダー#includeがそれらの後に表示される可能性があることを知ることができないためです。)
討論
つまり、実装ファイルで#includeディレクティブの後に宣言とディレクティブを自由に使用して名前空間を使用でき、使用する必要があります。反対の主張が繰り返されているにもかかわらず、宣言とディレクティブを使用した名前空間は悪ではなく、名前空間の目的を損なうことはありません。むしろ、それらは名前空間を使用可能にするものです。
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::sin
、std::cos
...)よりも優れています。これは、短く、ユーザー定義の浮動小数点型(引数依存のルックアップ(ADL)を介して)を処理できるためです。
グローバルに使用しないでください
グローバルに使用された場合にのみ「不良」と見なされます。理由:
- プログラミングしている名前空間が乱雑になります。
- 多くのを使用すると、読者は特定の識別子がどこから来たのかを理解するのが困難になります
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::swap
forvalue_
、すなわちを選択しますvoid std::swap(int, int)
。 - オーバーロードが
void swap(Child&, Child&)
実装されている場合、コンパイラはそれを選択します。 - その過負荷がない場合、コンパイラーは
void std::swap(Child&,Child&)
これらを使用して最善の交換を試みます。
C ++ 11では、このパターンを使用する理由はもうありません。の実装はstd::swap
、潜在的な過負荷を見つけて選択するように変更されました。
もう一つの理由は驚きです。
私が見るならcout << blah
、std::cout << blah
私が思う代わりに:これは何cout
ですか?正常cout
ですか?何か特別なものですか?
経験豊富なプログラマーは、問題を解決するものは何でも使用し、新しい問題を引き起こすものはすべて回避します。また、この正確な理由から、ヘッダーファイルレベルのusingディレクティブを回避します。
経験豊富なプログラマーは、ソースファイル内の名前の完全な修飾を避けようとします。これのマイナーな理由は、正当な理由がない限り、より少ないコードで十分な場合に、より多くのコードを書くことはエレガントではないということです。これの主な理由は、引数依存ルックアップ(ADL)をオフにすることです。
これらの正当な理由は何ですか?プログラマーが明示的にADLをオフにしたい場合もあれば、明確にしたい場合もあります。
したがって、以下は問題ありません。
- 関数の実装内の関数レベルのusingディレクティブとusing宣言
- ソースファイル内のソースファイルレベルのusing宣言
- (時々)ソースファイルレベルのusingディレクティブ
グローバルに使用すべきではないことに同意しますが、のようにローカルで使用することはそれほど悪いことではありません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
)によって別のスコープでアクセス可能にされた名前よりも優先されます。
また、それは悪い習慣だと思います。どうして?ある日、名前空間の機能はものを分割することだと思ったので、すべてを1つのグローバルバッグに投げ込んでそれを台無しにすべきではありません。
ただし、「cout」と「cin」を頻繁に使用する場合using std::cout; using std::cin;
は、.cppファイルに次のように記述します(ヘッダーファイルでは伝播しないため#include
)。誰も正気の人がストリームcout
やに名前を付けることはないと思いますcin
。;)
コードを見て、それが何をするのかを知るのは素晴らしいことです。私が見れば、それが図書館の流れstd::cout
だとわかってcout
いstd
ます。私が見るならcout
、私は知りません。それは図書館の流れかもしれません。または、同じ関数で10行高くなる可能性があります。または、そのファイルで指定された変数。それは何でもかまいません。cout
std
int cout = 0;
static
cout
ここで、特に大きくない100万行のコードベースを取得します。バグを探しています。つまり、この100万行の中に、本来の機能を果たさない行が1つあることがわかります。名前付きをcout << 1;
読み取り、それを1ビット左にシフトして、結果を破棄することができます。バグを探して、それをチェックする必要があります。私が本当に本当に見たいと思っていることがわかりますか?static int
cout
std::cout
あなたが教師であり、生活のためにコードを書いたり維持したりする必要がなかったなら、それは本当に良い考えのように思えるこれらのことの1つです。私はコードを見るのが大好きです。(1)コードの機能を知っています。そして、(2)それを書いている人はそれが何をするのか知っていたと私は確信しています。
複雑さを管理することがすべてです。名前空間を使用すると、不要なものが引き込まれ、デバッグが困難になる可能性があります(おそらくそう言います)。std ::を使用すると、あらゆる場所で読みにくくなります(より多くのテキストなど)。
コースのための馬-あなたが最善を尽くし、できると感じる方法であなたの複雑さを管理します。
検討する
// myHeader.h
#include <sstream>
using namespace std;
// someoneElses.cpp/h
#include "myHeader.h"
class stringstream { // Uh oh
};
これは単純な例であることに注意してください。20個のインクルードとその他のインポートを含むファイルがある場合、問題を理解するために通過する依存関係が大量にあります。さらに悪いことに、競合する定義によっては、他のモジュールで無関係なエラーが発生する可能性があります。
ひどいことではありませんが、ヘッダーファイルやグローバル名前空間で使用しないことで頭痛の種を減らすことができます。非常に限られた範囲でそれを行うことはおそらく大丈夫ですが、私の関数がどこから来ているのかを明確にするために余分な5文字を入力するのに問題はありませんでした。
懸念を明確にするための具体例。2つのライブラリがfoo
ありbar
、それぞれに独自の名前空間がある状況があるとします。
namespace foo {
void a(float) { /* Does something */ }
}
namespace bar {
...
}
ここで、次のように独自のプログラムで一緒に使用するfoo
とbar
します。
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
、他の名前空間よりも(その名前空間に含まれるものの数が多いために)名前空間を使用することはさらに不快になる可能性があります。
最終的に、これは書き込み可能性と信頼性/保守性の間のトレードオフです。読みやすさも考慮に入れるかもしれませんが、私はそれがどちらの方向にも進んでいるという議論を見ることができました。通常、信頼性と保守性の方が重要だと思いますが、この場合、かなりまれな信頼性/保守性の影響に対して、書き込み可能性のコストを常に支払うことになります。「最良の」トレードオフは、プロジェクトと優先順位を決定します。
同時に多くの名前空間を使用することは明らかに災害のレシピですが、再定義は自分のコードによってのみ発生する可能性があるため、JUST名前空間std
と名前空間のみを使用std
することは私の意見ではそれほど大きな問題ではありません...
したがって、それらを「int」や「class」などの予約名として機能すると考えてください。それだけです。
人々はそれについてそんなに肛門になるのをやめるべきです。あなたの先生はずっと正しかった。1つの名前空間を使用するだけです。それが、そもそも名前空間を使用することの要点です。同時に複数を使用することは想定されていません。それがあなた自身のものでない限り。繰り返しになりますが、再定義は行われません。
あなたとは異なるスタイルやベストプラクティスの意見を持つ人々によって書かれたコードを読むことができる必要があります。
のみを使用している場合
cout
、誰も混乱することはありません。しかし、たくさんの名前空間が飛び交っていて、このクラスが表示され、それが何をするのか正確にわからない場合、名前空間を明示的にすることは、ある種のコメントとして機能します。一見すると、「ああ、これはファイルシステムの操作です」または「ネットワーク関連の処理を行っています」とわかります。
私はここで他の人たちに同意しますが、読みやすさに関する懸念に対処したいと思います-ファイル、関数、またはクラス宣言の先頭で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;
}
名前空間は名前付きスコープです。名前空間は、関連する宣言をグループ化し、個別の項目を個別に保持するために使用されます。たとえば、別々に開発された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
// ...
}
名前空間は、さまざまなライブラリやさまざまなバージョンのコードを管理するための強力なツールを提供します。特に、非ローカル名への参照を明示的に行う方法の代替案をプログラマーに提供します。
出典: BjarneStroustrupによるC ++プログラミング言語の概要
using namespace std
カウントのあいまいさのためにコンパイルエラーをスローする例。これはアルゴリズムライブラリの関数でもあります。
#include <iostream>
#include <algorithm>
using namespace std;
int count = 1;
int main() {
cout << count << endl;
}
ソフトウェアやプロジェクトのパフォーマンスを悪化させることはありません。ソースコードの先頭に名前空間を含めることは悪くありません。using namespace std
指示が含まれるかどうかは、ニーズやソフトウェアまたはプロジェクトの開発方法によって異なります。
にnamespace std
は、C ++の標準関数と変数が含まれています。この名前空間は、C ++標準関数を頻繁に使用する場合に役立ちます。
このページで言及されているように:
名前空間stdを使用するステートメントは、一般的に悪い習慣と見なされます。このステートメントの代わりに、型を宣言するたびにスコープ演算子(::)を使用して、識別子が属する名前空間を指定します。
そして、この意見を参照してください:
名前空間を多用し、何も衝突しないことが確実にわかっている場合は、ソースファイルで「usingnamespacestd」を使用しても問題はありません。
using namespace std
その名前空間からすべての関数と変数を呼び出すため、ソースファイルにを含めるのは悪い習慣だと言う人もいます。に含まれている別の関数と同じ名前で新しい関数を定義するnamespace std
場合、関数をオーバーロードし、コンパイルまたは実行によって問題が発生する可能性があります。期待どおりにコンパイルまたは実行されません。
このページで言及されているように:
このステートメントを使用すると、std ::と入力する必要がなくなりますが、std名前空間で定義されたクラスまたは型にアクセスする場合は常に、std名前空間全体がプログラムの現在の名前空間にインポートされます。これがそれほど良いことではない理由を理解するために、いくつかの例を見てみましょう
..。
開発の後の段階で、「foo」と呼ばれるライブラリにカスタム実装された別のバージョンのcoutを使用したいと思います(たとえば)
..。
coutが指しているライブラリがあいまいであることに注意してください。コンパイラはこれを検出し、プログラムをコンパイルしない場合があります。最悪の場合、識別子が属する名前空間を指定したことがないため、プログラムはコンパイルされても間違った関数を呼び出す可能性があります。
すべての条件下で必ずしも悪い習慣だとは思いませんが、使用するときは注意が必要です。ライブラリを作成している場合は、名前空間でスコープ解決演算子を使用して、ライブラリが他のライブラリと頭をぶつけないようにする必要があります。アプリケーションレベルのコードについては、何も問題はありません。
私は他の人に同意します-それは名前の衝突、曖昧さを求めています、そしてそれから事実はそれがあまり明白ではないということです。の使用法はわかりますがusing
、個人的な好みはそれを制限することです。また、他の人が指摘したことも強く検討します。
かなり一般的な名前である可能性がある関数名を検索したいが、std
名前空間でのみ検索したい場合(またはその逆-名前空間、名前空間、...にないすべての呼び出しを変更したい場合)、では、これをどのように提案しますか?std
X
それを行うためのプログラムを書くこともできますが、プロジェクトを維持するためのプログラムを書くよりも、プロジェクト自体に時間を費やすほうがよいのではないでしょうか。
個人的には、std::
プレフィックスは気にしません。私はそれを持っていないよりも見た目が好きです。それが明示的で「これは私のコードではありません...私は標準ライブラリを使用しています」と言っているからなのか、それとも他のものなのかはわかりませんが、見た目は良いと思います。私が最近C ++を始めたばかりであることを考えると、これは奇妙かもしれません(Cや他の言語をずっと長く使用していて、Cはアセンブリのすぐ上で私のお気に入りの言語です)。
上記や他の人の指摘と多少関係がありますが、もう一つあります。これは悪い習慣かもしれませんが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にもっと適合します(しかし、それは自分自身をa。別の言語を学び、b。オブジェクト/クラスなどに対して偏見を少なくしないようにするための良い演習であり、良い方法でした。偏見が少なく、傲慢でなく、より受け入れやすいものとして。)しかし、何がある便利なことは、一部が既に提案するものである:私は確かに私が何をした場合、名前が衝突する原因となる2名前を付けるためにソート(同じことを)(?それはかなり一般的で、それはない)リストを使用し、かusing namespace std;
、などをそのために、私は具体的で、管理し、それを標準的な使用法にするつもりなら、それを指定しなければならないことを知っていることを好みます。簡単に言えば、許可されているとは限りません。
そして、Boostの正規表現をの一部にすることに関してstd
。私は将来の統合のためにそれを行います、そして-繰り返しますが、これはバイアスであることを完全に認めます-私はそれがほど醜いとは思わないboost::regex:: ...
。確かに、それは私にとって別のことです。C ++には、外観とメソッドでまだ完全に受け入れられていないことがたくさんあります(別の例:可変個引数テンプレートとvar引数[可変個引数テンプレートは非常に便利です!])。私が受け入れるものでさえそれは困難でした、そして私はまだ彼らに問題を抱えています。
私の経験から、say、を使用するライブラリが複数あるcout
が、目的が異なる場合は、間違っcout
たを使用する可能性があります。
たとえば、(または)ではなく、「using namespace std;
and」using namespace otherlib;
と「just」cout
(たまたま両方にある)と入力すると、間違ったものを使用してエラーが発生する可能性があります。を使用する方がはるかに効果的で効率的です。std::cout
'otherlib::cout'
std::cout
ケースバイケースです。ソフトウェアの「総所有コスト」をその存続期間にわたって最小限に抑えたいと考えています。「名前空間stdを使用する」と述べるにはいくらかのコストがかかりますが、それを使用しないと読みやすさにもコストがかかります。
人々は、それを使用するときに、標準ライブラリが新しいシンボルと定義を導入すると、コードのコンパイルが停止し、変数の名前を変更せざるを得なくなる可能性があることを正しく指摘しています。それでも、これはおそらく長期的には良いことです。なぜなら、ある驚くべき目的でキーワードを使用している場合、将来のメンテナは一時的に混乱したり気を散らしたりするからです。
たとえば、他の人に知られているベクターではない、ベクターと呼ばれるテンプレートは必要ありません。そして、このようにC ++ライブラリに導入された新しい定義の数は十分に少ないので、単純に思いつかないかもしれません。そこでの変化のこの種を行うに持つのコストは、しかし、コストは高くなく、使用しないことによって得られる明快によって相殺されstd
、他の目的のためにシンボル名を。
クラス、変数、および関数の数を考えるとstd::
、すべてについて述べると、コードが50%フラフになり、頭を動かすのが難しくなる可能性があります。1画面のコードに取り込むことができるアルゴリズムまたはメソッドのステップでは、フォローするために前後にスクロールする必要があります。これは実際のコストです。おそらくそれは高額ではないかもしれませんが、それが存在することさえ否定する人々は、経験が浅い、独断的、または単に間違っています。
私は次のルールを提供します:
std
他のすべてのライブラリとは異なります。これは、基本的に誰もが知っておく必要のある1つのライブラリであり、私の見解では、言語の一部として考えるのが最善です。一般的に言ってusing namespace std
、他の図書館がなくても、優れたケースがあります。これ
using
をヘッダーに入れて、コンパイルユニット(.cppファイル)の作成者に決定を強制しないでください。決定は常にコンパイルユニットの作成者に任せてください。using namespace std
どこでも使用することを決定したプロジェクトでも、そのルールの例外として最も適切に処理されるいくつかのモジュールに問題がない場合があります。名前空間機能を使用すると、シンボルが同じように定義された多くのモジュールを使用できますが、そうすることは混乱を招きます。可能な限り名前を変えてください。名前空間機能を使用していない場合でも、という名前のクラスがあり、という名前のクラス
foo
をstd
導入する場合は、foo
とにかくクラスの名前を変更する方が長期的にはおそらく良いでしょう。名前空間を使用する代わりに、シンボルにプレフィックスを付けて手動で名前空間を付けることもできます。私は何十年も使用してきた2つのライブラリを持っています。どちらもCライブラリとして始まり、実際には、すべてのシンボルの前に「AK」または「SCWin」が付いています。一般的に言えば、これは「使用」構造を回避するようなものですが、ツインコロンは記述しません。
AK::foo()
代わりにAKFoo()
です。これにより、コードの密度が5〜10%低くなり、冗長性が低下します。唯一の欠点は、同じプレフィックスを持つ2つのそのようなライブラリを使用する必要がある場合に大きな問題が発生することです。X Windowライブラリは、いくつかの#definesでそうするのを忘れていることを除いて、この点で優れていることに注意してください。TRUEとFALSEはXTRUEとXFALSEである必要があり、これにより、同様にTRUEとFALSEを使用するSybaseまたはOracleとの名前空間の衝突が設定されます。異なる値で!(データベースの場合はASCII 0および1です!)これの特別な利点の1つは、プリプロセッサ定義に適用されないように見えるのに対し、C ++using
/namespace
システムはそれらを処理しないことです。これの良い利点は、プロジェクトの一部から最終的にはライブラリになるまでの有機的な傾斜を与えることです。私の大規模なアプリケーションでは、すべてのウィンドウクラスにプレフィックスが付けられWin
、すべての信号処理モジュールがModなどになります。これらのいずれかが再利用される可能性はほとんどないため、各グループをライブラリにすることによる実用的なメリットはありませんが、プロジェクトがサブプロジェクトにどのように分割されるかが数秒で明らかになります。
修飾されていないインポートされた識別子では、識別子が宣言されている場所を見つけるためにgrepなどの外部検索ツールが必要です。これにより、プログラムの正当性についての推論が難しくなります。
それがどこにあるかによります。共通のヘッダーである場合は、名前空間をグローバル名前空間にマージすることにより、名前空間の値を減らしています。これは、モジュールをグローバルにするための優れた方法である可能性があることに注意してください。
これは悪い習慣であり、しばしばグローバル名前空間汚染として知られています。複数の名前空間が署名付きの同じ関数名を持っている場合、問題が発生する可能性があります。コンパイラがどれを呼び出すかを決定するのはあいまいになりますstd::cout
。のような関数呼び出しで名前空間を指定すると、これをすべて回避できます。お役に立てれば。:)
あなたの質問に答えるために、私はそれを実際にこのように見ています:多くのプログラマー(すべてではない)が名前空間stdを呼び出します。したがって、名前空間stdにあるものと同じ名前を衝突または使用するものを使用しない習慣を身に付ける必要があります。これは当然のことですが、厳密に言えば、考えられる一貫性のある単語や仮名の数と比べるとそれほど多くはありません。
私は本当に...「これが存在することに依存しないでください」と言うことは、それが存在しないことに依存するようにあなたを設定しているだけです。コードスニペットの借用と修復の問題が常に発生します。ユーザー定義および借用したものを本来あるべき範囲に限定し、グローバルを非常に控えめにします(正直なところ、グローバルは「今すぐコンパイルし、後で正気にする」ための最後の手段である必要があります)。stdを使用すると「cout」と「std :: cout」の両方で機能しますが、stdを使用しないと「std :: cout」でのみ機能するため、先生からのアドバイスは悪いと思います。自分のコードをすべて書くことができるとは限りません。
注:コンパイラーの動作について実際に少し学ぶまでは、効率の問題にあまり焦点を当てないでください。コーディングの経験が少しあれば、優れたコードを単純なものに一般化できることに気付く前に、それらについてそれほど多くを学ぶ必要はありません。まるでCですべてを書いたかのように、あらゆる点で単純です。優れたコードは、必要なだけ複雑です。