GeeksforGeeks
On 1月 16, 2022 by adminusing namespace std という文は一般的にバッドプラクティスとみなされます。 このステートメントの代替案は、型を宣言するたびにスコープ演算子(::)を使用して識別子が属する名前空間を指定することです。
std 名前空間で定義されたクラスや型にアクセスしたいときに std:: と入力する手間が省けますが、std 名前空間全体をプログラムの現在の名前空間にインポートしてしまうことになります。 このことがなぜ良くないのか、いくつかの例を見てみましょう
例えば、std名前空間からcoutを使いたいとします。 そこで、
例 1 と書きます。
#include <iostream>
using
namespace std;
cout <<
" Something to Display"
;
Now at later stage of development, foo “と呼ばれるライブラリでカスタム実装された別のバージョンのcoutを使用したい(例)
#include <foo.h>
#include <iostream>
using
namespace
std;
cout <<
" Something to display"
;
どうあいまいであるかに注意してください。 は、どのライブラリを指しているのでしょうか? コンパイラはこれを検知して、プログラムをコンパイルしないかもしれません。 最悪の場合、プログラムはコンパイルされますが、識別子がどの名前空間に属しているかを指定しなかったため、間違った関数を呼び出してしまうかもしれません。 これにより、2 つのオブジェクトが同じ名前を持ちながら、異なる名前空間に属している場合は異なる扱いを受けることが保証されます。 この例では、正反対のことが起こっていることに注目してください。 名前の競合を解決するのではなく、実際に名前の競合が発生しています。
名前空間をインポートする場合、本質的にすべての型定義を現在のスコープに引き込んでいます。 std 名前空間は巨大です。 std 名前空間は巨大で、何百もの定義済み識別子があるため、開発者が意図するオブジェクトの別の定義が std ライブラリにあることを見落としてしまう可能性があります。 このことを知らずに、自分自身の実装を指定し、それがプログラムの後の部分で使用されることを期待してしまうかもしれません。 このように、現在の名前空間には同じ型に対して2つの定義が存在することになります。 これは C++ では許されないことで、たとえプログラムがコンパイルされたとしても、どの定義がどこで使われているのかを知る方法はありません。 したがって、上記の例に対する一つの可能な解決策は、
#include <foo>
#include <iostream>
std::cout <<
"Something to display"
;
foo::cout <
"Something to display"
;
しかし std をタイプしなければならないのは残念です。: をタイプしなければならないのは面倒です。 また、型定義がたくさんあるため、コードが毛深くなり、コードを読むのが難しくなります。 例えば、プログラム
例2の現在の時刻を取得するコードを考えてみましょう。
#include <chrono>
#include <iostream>
auto
start = std::chrono::high_performance_clock::now()
auto
stop
= std::chrono::high_peformance_clock::now();
auto
duration
= std::duration_cast<std::chrono::milliseconds>(stop - start);
複雑で長い型定義が散見されるソースコードは、とても読みやすいとは言えません。 このジレンマを解決するいくつかの方法があります。すなわち、std キーワードでコードを散らかさずに正確な名前空間を指定することです。 この例では、1, 2 つの typedef を使用して問題を解決できます。1 つは標準ライブラリ用、もう 1 つは foo
#include <foo>
#include <iostream>
typedef
std::cout cout_std;
typedef
foo::cout cout_foo;
cout_std <<
"Something to write"
;
cout_foo <<
"Something to write"
;
名前空間全体をインポートする代わりに。 切り詰めた名前空間をインポートする
例 2 では、std.NET の下にある chrono 名前空間だけをインポートすることができました。
#include <chrono>
#include <iostream>
using
std::chrono;
auto
start = high_performance_clock::now();
auto
stop = high_performance_clock::now();
auto
duration duration_cast<milliseconds>(stop - start);
また、単一の識別子をインポートするためのステートメントを使用することができます。 std::cout のみをインポートするには、
using std::cout;
それでも名前空間全体をインポートする場合は、グローバルスコープではなく、関数内または限られたスコープで行うようにします。 そうすることで、名前空間の定義がローカルスコープにインポートされ、少なくとも、起こりうるエラーが発生した場合、その原因がどこにあるのかを知ることができます。
#include <isotream>
using
namespace
std;
void
foo()
{
using
namespace
std;
}
結論です。
名前空間から識別子にアクセスするための代替方法について説明しました。 すべての場合において、ソースコードに名前空間全体をインポートすることは避けてください。
While good coding practices may take some time to learn and develop, but they generally pay out in the long run. クリーンで曖昧さのない、堅牢でエラーのないコードを書くことは、あらゆるプログラミング開発者の意図であるべきです。
コメントを残す