私は他の人から、コードを書くのは間違っているので、代わりに直接using namespace std;
使うべきだと言われました。std::cout
std::cin
なぜusing namespace std;
悪い習慣と見なされるのですか?それは非効率的ですか、それともあいまいな変数(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.0は、何年にもわたって呼び出されたコードよりも、Quux()
いくつかの呼び出しに明確に一致する関数を導入する可能性があります。その後、コードはコンパイルされますが、間違った関数をサイレントに呼び出し、god-knows-whatを実行します。それは物事が得ることができるのと同じくらい悪いです。Quux()
bar::Quux()
std
名前空間には大量の識別子があり、その多くは他のコードにも表示される可能性が非常に高い非常に一般的な識別子(、、、、など)であることに注意しlist
てsort
ください。string
iterator
これがありそうもないと考える場合: Stack Overflowで、この回答を行ってから約半年後に、ほぼ正確にこれが発生した(プレフィックスが省略されたために間違った関数が呼び出された)という質問がありました。これは、そのような質問のもう1つの最近の例です。ですから、これは本当の問題です。std::
もう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:";
最近、 VisualStudio2010に関する苦情に遭遇しました。ほとんどすべてのソースファイルに次の2行が含まれていることが判明しました。
using namespace std;
using namespace boost;
多くのBoost機能がC++0x標準に組み込まれ、VisualStudio2010には多くのC++0x機能があるため、突然これらのプログラムがコンパイルされなくなりました。
したがって、回避using namespace X;
は将来を保証する形式であり、使用中のライブラリやヘッダーファイルへの変更がプログラムを壊さないようにする方法です。
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;
。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
for value_
、すなわちを選択します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をオフにしたい場合もあれば、曖昧さを解消したい場合もあります。
したがって、以下は問題ありません。
グローバルに使用すべきではないことに同意しますが、のようにローカルで使用することはそれほど悪いことではありません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
だとわかっています。私が見るなら、私は知りません。それは図書館の流れかもしれません。または、同じ関数で10行高くなる可能性があります。または、そのファイルで指定された変数。それは何でもかまいません。cout
std
cout
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
名前空間に含まれるものが多いほど、競合のリスクが高くなるため、他の名前空間よりも(その名前空間に含まれるものの数が多いために)名前空間を使用することはさらに不快になる可能性があります。
最終的に、これは書き込み可能性と信頼性/保守性の間のトレードオフです。読みやすさも考慮に入れるかもしれませんが、私はそれがどちらの方向にも進んでいるという議論を見ることができました。通常、信頼性と保守性の方が重要だと思いますが、この場合、かなりまれな信頼性/保守性の影響に対して、書き込み可能性のコストを常に支払うことになります。「最良の」トレードオフは、プロジェクトと優先順位を決定します。
あなたとは異なるスタイルやベストプラクティスの意見を持つ人々によって書かれたコードを読むことができる必要があります。
のみを使用している場合cout
、誰も混乱することはありません。しかし、たくさんの名前空間が飛び交っていて、このクラスが表示され、それが何をするのか正確にわからない場合、名前空間を明示的にすることは、ある種のコメントとして機能します。一見すると、「ああ、これはファイルシステム操作です」または「ネットワーク関連の処理を行っています」とわかります。
同時に多くの名前空間を使用することは明らかに災害のレシピですが、再定義は自分のコードによってのみ発生する可能性があるため、名前空間だけを使用して名前空間std
だけを使用することは、私の意見ではそれほど大きな問題ではありません...std
したがって、それらを「int」や「class」などの予約名として機能すると考えてください。それだけです。
人々はそれについてそんなに肛門的であることをやめるべきです。あなたの先生はずっと正しかった。1つの名前空間を使用するだけです。それが、そもそも名前空間を使用することの要点です。同時に複数を使用することは想定されていません。それがあなた自身のものでない限り。繰り返しになりますが、再定義は行われません。
私はここで他の人たちに同意しますが、読みやすさに関する懸念に対処したいと思います-ファイル、関数、またはクラス宣言の先頭で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++プログラミング言語の概要
countのあいまいさのためにコンパイルエラーをスローする例。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が指しているライブラリがあいまいであることに注意してください。コンパイラはこれを検出し、プログラムをコンパイルしない場合があります。最悪の場合、識別子が属する名前空間を指定しなかったため、プログラムはコンパイルされても間違った関数を呼び出す可能性があります。
ケースバイケースです。ソフトウェアの「総所有コスト」を、その存続期間にわたって最小限に抑えたいと考えています。「名前空間stdを使用する」と述べるにはいくらかのコストがかかりますが、それを使用しないと読みやすさにもコストがかかります。
人々は、それを使用するときに、標準ライブラリが新しいシンボルと定義を導入すると、コードのコンパイルが停止し、変数の名前を変更せざるを得なくなる可能性があることを正しく指摘しています。それでも、これはおそらく長期的には良いことです。なぜなら、ある驚くべき目的でキーワードを使用している場合、将来のメンテナは一時的に混乱したり気を散らしたりするからです。
たとえば、他の人に知られているベクトルではないベクトルと呼ばれるテンプレートは必要ありません。そして、このようにC ++ライブラリに導入された新しい定義の数は十分に少ないので、単純に思いつかないかもしれません。この種の変更を行うにはコストがかかりますが、コストは高くなく、他の目的でシンボル名を使用しないことによって得られる明確さによって相殺されますstd
。
クラス、変数、および関数の数を考えると、std::
すべてについて述べると、コードが50%フラフになり、頭を動かすのが難しくなる可能性があります。1画面のコードに取り込むことができるアルゴリズムまたはメソッドのステップでは、フォローするために前後にスクロールする必要があります。これは実際のコストです。おそらくそれは高額ではないかもしれませんが、それが存在することさえ否定する人々は、経験が浅い、独断的、または単に間違っています。
私は次のルールを提供します:
std
他のすべてのライブラリとは異なります。これは、基本的に誰もが知っておく必要のある1つのライブラリであり、私の見解では、言語の一部として考えるのが最適です。一般的に言ってusing namespace std
、他の図書館がない場合でも、優れたケースがあります。
using
これをヘッダーに入れて、コンパイル単位(.cppファイル)の作成者に決定を強制しないでください。決定は常にコンパイルユニットの作成者に任せてください。どこでも使用することを決定したプロジェクトでも、using namespace std
そのルールの例外として最も適切に処理されるいくつかのモジュールに問題がない場合があります。
名前空間機能を使用すると、シンボルが同じように定義された多くのモジュールを使用できますが、そうすることは混乱を招きます。可能な限り名前を変えてください。名前空間機能を使用していない場合でも、という名前のクラスがあり、という名前のクラスfoo
をstd
導入する場合は、foo
とにかくクラスの名前を変更する方が長期的にはおそらく良いでしょう。
名前空間を使用する代わりに、シンボルにプレフィックスを付けて手動で名前空間を付けることもできます。私は何十年も使用してきた2つのライブラリを持っています。どちらもCライブラリとして始まり、実際には、すべてのシンボルの前に「AK」または「SCWin」が付いています。一般的に、これは「using」構造を回避するようなものですが、ツインコロンは記述しません。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など。これらのいずれかが再利用される可能性はほとんどないため、各グループをライブラリにすることによる実際的なメリットはありませんが、プロジェクトがサブプロジェクトに分割される方法が数秒で明らかになります。
私は他の人に同意します-それは名前の衝突、曖昧さを求めています、そしてそれから事実はそれがあまり明白ではないということです。の使用法はわかりますがusing
、個人的な好みはそれを制限することです。また、他の人が指摘したことも強く検討します。
かなり一般的な名前である可能性がある関数名を検索したいが、名前空間でのみ検索したい場合(またはその逆-名前空間、名前空間、...にないstd
すべての呼び出しを変更したい場合)、では、これをどのように提案しますか?std
X
それを行うためのプログラムを書くこともできますが、プロジェクトを維持するためのプログラムを書くよりも、プロジェクト自体に時間を費やすほうがよいのではないでしょうか。
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;
}
それが悪い考えであるかどうかについては議論しません。しかし、私はそれが私のプロジェクトのためにそれをきれいに保つと同時にそれを具体的にすることを主張します:確かに、私はBoostを使わなければなりません、しかし私はlibstdc++が最終的にそれを持っているようにそれを使っています。はい、独自のプロジェクトを開始し、最初に標準(...)から開始することは、メンテナンス、開発、およびプロジェクトに関連するすべてのことを支援するのに非常に役立ちます。
何かを明確にするために:STLでクラスの名前などを意図的に、より具体的には代わりに使用することは、実際には良い考えではないと思います。私は「文字列」のアイデアが気に入らなかったので、文字列は例外です(最初、上記、または2番目を無視します。必要に応じてしゃれます)。
現状では、私はまだCに非常に偏っていて、C++に偏っています。詳細を控えて、私が取り組んでいることの多くはCにもっと適合します(しかし、それは自分自身をa。別の言語を学び、b。オブジェクト/クラスなどに対して偏見を少なくしないようにするための良い練習と良い方法でした。偏見が少なく、傲慢でなく、より受け入れやすいものとして。)しかし、有用なのは、すでに提案されていることです。私は実際にリストを使用し(かなり一般的ですが、そうではありませんか?)、(同じことで)2つに名前を付けて、名前が衝突するように並べ替えますusing namespace std;
。そのために、私は具体的で、管理し、それを標準的な使用法にするつもりなら、それを指定しなければならないことを知っていることを好みます。簡単に言えば、許可されているとは限りません。
そして、Boostの正規表現をの一部にすることに関してstd
。私は将来の統合のためにそれを行います、そして-繰り返しますが、これはバイアスであることを完全に認めます-私はそれがほど醜いとは思わないboost::regex:: ...
。確かに、それは私にとって別のことです。C ++には、外観とメソッドでまだ完全に受け入れられていないことがたくさんあります(別の例:可変個引数テンプレートとvar引数[可変個引数テンプレートは非常に便利です!])。私が受け入れるものでさえそれは困難でした、そして私はまだ彼らに問題を抱えています。
私の経験から、sayを使用する複数のライブラリがあるcout
が、別の目的で使用する場合は、間違ったを使用する可能性がありますcout
。
たとえば、(または)ではなく、と入力し、(両方にある)using namespace std;
だけusing namespace otherlib;
を入力すると、間違ったものを使用してエラーが発生する可能性があります。を使用する方がはるかに効果的で効率的です。cout
std::cout
'otherlib::cout'
std::cout
すべての条件下で必ずしも悪い習慣ではないと思いますが、使用するときは注意が必要です。ライブラリを作成している場合は、名前空間でスコープ解決演算子を使用して、ライブラリが他のライブラリと頭をぶつけないようにする必要があります。アプリケーションレベルのコードについては、何も問題はありません。
修飾されていないインポートされた識別子では、識別子が宣言されている場所を見つけるためにgrepなどの外部検索ツールが必要です。これにより、プログラムの正当性についての推論が難しくなります。
「なぜ'名前空間stdを使用しているのですか;' C ++では悪い習慣だと考えられていますか?」
逆に言えば、5つの余分な文字を入力するのが面倒だと考える人がいるのはなぜですか?
たとえば、数値ソフトウェアを作成することを検討してください。「vector」が問題のドメインの最も重要な概念の1つであるのに、なぜ一般的な「std ::vector」を「vector」に切り詰めてグローバル名前空間を汚染することを検討するのでしょうか。
これは悪い習慣であり、しばしばグローバル名前空間汚染として知られています。複数の名前空間が署名付きの同じ関数名を持っている場合、問題が発生する可能性があります。コンパイラがどれを呼び出すかを決定するのはあいまいであり、のような関数呼び出しで名前空間を指定する場合、これはすべて回避できますstd::cout
。お役に立てれば。:)
それはそれがどこにあるかに依存します。共通のヘッダーである場合は、名前空間をグローバル名前空間にマージすることにより、名前空間の値を減らしています。これは、モジュールをグローバルにするための優れた方法である可能性があることに注意してください。
あなたの質問に答えるために、私はそれを実際にこのように見ています:多くのプログラマー(すべてではない)が名前空間stdを呼び出します。したがって、名前空間stdにあるものと同じ名前を衝突または使用するものを使用しない習慣を身に付ける必要があります。これは当然のことですが、厳密に言えば、考えられる一貫性のある単語や仮名の数と比べるとそれほど多くはありません。
私は本当に...「これが存在することに依存しないでください」と言うことは、それが存在しないことに依存するようにあなたを設定しているだけです。コードスニペットの借用と修復の問題が常に発生します。ユーザー定義および借用したものを本来あるべき範囲に限定し、グローバルを非常に控えめにします(正直なところ、グローバルは「今すぐコンパイルし、後で正気にする」ための最後の手段である必要があります)。stdを使用すると「cout」と「std::cout」の両方で機能しますが、stdを使用しないと「std :: cout」でのみ機能するため、先生からのアドバイスは悪いと思います。自分のコードをすべて書くことができるとは限りません。
注:コンパイラーの動作について実際に少し学ぶまでは、効率の問題にあまり焦点を当てないでください。コーディングの経験が少しあれば、優れたコードを単純なものに一般化できることを理解する前に、それらについてそれほど多くを学ぶ必要はありません。すべてをCで書いたかのように、すべてのビットが単純です。優れたコードは、必要なだけ複雑です。
正直なところ、私にとっては、インデントするスペースの数について話し合うようなものです。
ヘッダーでディレクティブを使用すると、損傷が発生します。しかし、C ++ファイルでは?たぶん、一度に2つの名前空間を使用する場合。しかし、それを使用する場合、それは実際の効率よりもスタイルに関するものです。
インデントに関するスレッドがなぜそれほど人気があるのか知っていますか?誰でもそれについて何かを言うことができ、非常に賢く経験豊富に聞こえます。
非常に簡単な答えがあります:それは防御的なプログラミングです。、などの使用はstd::size_t
、次の方法で少し簡単にできることをご存知でしょう。このようなディレクティブがヘッダーにないことを確信する必要がないことを願っています。ただし、翻訳ユニット内では、誘惑される可能性があります...std::cout
using namespace std;
名前空間の一部であるタイプ、クラスなどは、std
C++のリビジョンごとに増加します。std::
修飾子を緩和すると、潜在的なあいまいさが多すぎます。頻繁に使用する名前の修飾子を緩和することは完全に合理的です。たとえば、次のようになります。-ただし、これらが言語の十分に理解されている部分(または具体的にはCのラッピング)でない限り、ライブラリ)、修飾子を使用するだけです。std
using std::fprintf;
using std::size_t;
std
を使用しtypedef
、組み合わせてauto
推論decltype
することができれば、読みやすさ/保守性の観点から得られるものは実際には何もありません。
#include <iostream>
using namespace std;
int main() {
// There used to be
// int left, right;
// But not anymore
if (left != right)
std::cout << "Excuse me, WHAT?!\n";
}
なぜ?これは、一般的に使用される変数名と重複する識別子を取り込み、このコードをコンパイルして、を意味すると解釈できるためですif (std::left != std::right)
。
PVS-Studioは、V1058診断を使用してこのようなエラーを見つけることができます:https ://godbolt.org/z/YZTwhp (Andrey Karpovに感謝します!!)。
cppcheck開発者へのping:これにフラグを立てることができます。それはやっかいでした。
はい、名前空間は重要です。プロジェクトに入ると、1つのvar宣言をソースコードにインポートする必要がありましたが、コンパイル時に別のサードパーティライブラリと競合していました。
最後に、他の方法で回避し、コードをわかりにくくする必要がありました。
ローカルまたはグローバルでの使用は、アプリケーションに依存する必要があると思います。
なぜなら、ライブラリをローカルで使用する場合、コードが実際に混乱することがあるからです。読みやすさが低下します。
したがって、競合の可能性がある場合にのみ、ライブラリをローカルで使用する必要があります。
私は経験豊富な人ではありません。だから、私が間違っているかどうか私に知らせてください。
名前空間は、名前の競合を避けるためのものです。C ++はCに基づいており、異なるライブラリの関数が衝突することがあるため、Cには関数名と変数名に関する多くの問題があります。そのため、ライブラリ開発者は、関数の前に次のようなライブラリ名を付けるようになりました。
foo/foo.h
:
void libfoo_foo_foo_h_open(); // the name can be weird then even this one!
C ++は、この問題を簡単な方法で解決するために名前空間を導入しました。
file
それぞれファイルとウィンドウを処理するという名前の2つのライブラリwindow
と、次のコードがあるとします。
#include <file.h>
#include <window.h>
using namespace file;
using namespace window;
void open() {
...
}
file.h
:
namespace file {
void open(); // What!
}
window.h
:
namespace window {
void open(); // Oh no!
}
上記のコードは確実にそして確実にコンパイルに失敗します。
タイプstd::
(5文字のみ)が気に入らない場合は、いつでもこれを行うことができます:(ヘッダーファイルではお勧めできません)
using s = std;
それでもソースファイルで使用したい場合using namespace std;
は、その問題を招いているので、「名前空間の目的は何ですか?」と尋ねる必要があります。
using namespace std;
これは、名前の衝突の問題につながる可能性のある例を示しています。
この例では、非常に一般的なアルゴリズム名(std::count
)名が、非常に妥当な変数名()と衝突しますcount
。
これは、他のどの回答にも見当たらない観点です。1つの名前空間のみを使用してください。ほとんどの回答によると、名前空間が悪い主な理由は、関数名が競合している可能性があり、その結果、全体が混乱する可能性があるためです。ただし、名前空間を1つだけ使用する場合、これは発生しません。どのライブラリを最もよく使用するか(多分using namespace std;
)を決定し、それを使い続けます。
目に見えないライブラリプレフィックスを持っていると考えることができます-std::vector
ちょうどになりvector
ます。私の意見では、これは両方の長所です。一方では、(名前空間で意図されているように)入力する必要のある量を減らし、他方では、明確さとセキュリティのためにプレフィックスを使用する必要があります。名前空間プレフィックスのない関数またはオブジェクトがある場合、それは宣言した1つの名前空間からのものであることがわかります。
1つをグローバルに使用することにした場合は、他の1つをローカルで使用しないでください。これは、ローカル名前空間は便利さの多様性を提供するため、グローバル名前空間よりも有用であることが多いという他の答えに戻ります。
名前空間標準が使用される理由
C ++には、コンテナやアルゴリズムなど、アプリケーションの構築に使用する一般的な機能を含む標準ライブラリがあります。たとえば、キュークラスをグローバルに定義した場合など、これらで使用される名前が公開されていない場合は、競合することなく同じ名前を再度使用します。そこで、この変更を含めるために名前空間stdを作成しました。
使用しない理由1:悪い習慣
名前空間stdを使用するステートメントは、一般的に悪い習慣と見なされます。このステートメントの代わりに、型を宣言するたびにスコープ演算子(::)を使用して、識別子が属する名前空間を指定することもできます。このステートメントを使用すると、std ::と入力する必要がなくなりますが、std名前空間で定義されたクラスまたは型にアクセスする場合は常に、std名前空間全体をプログラムの現在の名前空間にインポートします。
使用しない理由2:コンパイラが混乱する
stdライブラリ全体をおもちゃのプログラムにインポートすることは問題ありませんが、本番グレードのコードでは、それは悪いことです。名前空間stdを使用します。名前空間stdで宣言されたすべてのシンボルに、名前空間修飾子なしでアクセスできるようにします。
例えば:
ここで、新しいバージョンのC ++にアップグレードし、知らないうちに新しいstd名前空間シンボルがプログラムに挿入されたとします。あなたはすでにあなたのプログラムでそれらのシンボルを使用しているかもしれません。これで、コンパイラーは、宣言されたシンボルが独自の実装に属しているのか、インポートした名前空間に属しているのかを判断するのに苦労します。一部のコンパイラはエラーをスローします。運が悪ければ、コンパイラは間違った実装を選択してコンパイルしますが、これは確かに実行時のクラッシュにつながります。
名前空間の汚染効果:
この方法は、たとえばコードでは問題ありませんが、std名前空間全体をグローバル名前空間に取り込むことは、名前空間の目的を損ない、名前の衝突につながる可能性があるため、適切ではありません。この状況は名前空間汚染と呼ばれます。
ヘッダーファイルで「usingnamespacestd」を使用しない限り、これは完全に正常なはずです。
たとえばboostと名前の競合がある場合は、特定の.cppファイルでこのステートメントを使用しませんが、他のファイルのすべての行で'std ::'を10回繰り返さないことで、すべての人の目と指を保存します。
残念ながら、これは今では純粋な宗教的な問題であり、誰もが「std::」を何度も繰り返すという確立されたパターンに従う方が簡単で生産的です。