声明 名前空間 std を使用する 一般に悪い習慣と考えられています。このステートメントの代替方法は、型を宣言するたびにスコープ演算子 (::) を使用して識別子が属する名前空間を指定することです。
このステートメントにより入力の手間が省けますが、 標準:: std 名前空間で定義されたクラスまたは型にアクセスする場合は常に、その名前空間全体がインポートされます。 標準 名前空間をプログラムの現在の名前空間に追加します。これがなぜそれほど良いことではないのかを理解するために、いくつかの例を挙げてみましょう
std 名前空間から cout を使用したいとします。それで私たちは書きます
例 1:
CPP
#include> using> namespace> std;> > cout <<>' Something to Display'>;> |
>
>
Cでポインタを逆参照する方法
開発の後半段階では、foo というライブラリにカスタム実装された別のバージョンの cout を使用したいと考えています (たとえば)
CPP
#include> #include> using> namespace> std;> > cout <<>' Something to display'>;> |
>
>
ここで、cout がどのライブラリを指しているのかというあいまいさがあることに注意してください。コンパイラはこれを検出し、プログラムをコンパイルしない場合があります。最悪の場合、識別子がどの名前空間に属しているかを指定していないため、プログラムはコンパイルできても間違った関数が呼び出される可能性があります。
名前空間は、識別子の名前の競合を解決するために C++ に導入されました。これにより、2 つのオブジェクトが同じ名前を持つことができ、異なる名前空間に属している場合は異なる方法で処理されることが保証されました。この例ではまったく逆のことが起こっていることに注目してください。名前の競合を解決する代わりに、実際には名前の競合を作成します。
名前空間をインポートすると、基本的にすべての型定義が現在のスコープに取り込まれます。 std 名前空間は巨大です。これには何百もの事前定義された識別子があるため、開発者は、std ライブラリに目的のオブジェクトの別の定義があるという事実を見落とす可能性があります。このことに気づかずに、独自の実装を指定し、それがプログラムの後の部分で使用されることを期待する可能性があります。したがって、現在の名前空間には同じ型に対して 2 つの定義が存在することになります。これは C++ では許可されておらず、プログラムがコンパイルされたとしても、どの定義がどこで使用されているかを知る方法はありません。
この問題の解決策は、スコープ演算子 (::) を使用して、識別子がどの名前空間に属するかを明示的に指定することです。したがって、上記の例に対する考えられる解決策の 1 つは次のとおりです。
二分木と二分探索木
CPP
#include> #include> > // Use cout of std library> std::cout <<>'Something to display'>;> > // Use cout of foo library> foo::cout <>'Something to display'>;> |
>
>
でも入力しなければならない 標準:: 毎回型を定義するのは面倒です。また、型定義が多くなるとコードがより毛深くなり、コードが読みにくくなります。たとえば、プログラム内の現在時刻を取得するコードを考えてみましょう。
例 2:
CPP
#include> #include> > auto> start = std::chrono::high_performance_clock::now()> > // Do Something> > auto> stop> >= std::chrono::high_peformance_clock::now();> auto> duration> >= std::duration_cast(stop - start);> |
>
>
複雑で長い型定義が散りばめられたソース コードは、あまり読みやすいものではありません。開発者にとってはコードの保守性が最も重要であるため、これは避けようとすることです。
このジレンマを解決するには、いくつかの方法があります。つまり、std キーワードをコードに散在させずに正確な名前空間を指定します。
typedef の使用を検討してください
typedef を使用すると、長い型定義を書く手間が省けます。例 1 では、std ライブラリ用と foo 用の 2 つの typedef を使用して問題を解決できます。
CPP
#include> #include> > typedef> std::cout cout_std;> typedef> foo::cout cout_foo;> > cout_std <<>'Something to write'>;> cout_foo <<>'Something to write'>;> |
>
>
名前空間全体をインポートする代わりに、切り詰められた名前空間をインポートします。
例 2 では、std の下に chrono 名前空間のみをインポートできます。
文字列比較のためのCプログラム
CPP
#include> #include> > // Import only the chrono namespace under std> using> std::chrono;> > auto> start = high_performance_clock::now();> > // Do Something> auto> stop = high_performance_clock::now();> auto> duration duration_cast(stop - start);> |
>
>
このステートメントを使用して、単一の識別子をインポートすることもできます。 std::cout のみをインポートするには、使用できます
using std::cout;>
それでも名前空間全体をインポートする場合は、グローバル スコープではなく、関数内または限定されたスコープ内で行うようにしてください。
関数定義またはクラス、構造体の定義内で using namespace std ステートメントを使用します。そうすることで、名前空間の定義がローカル スコープにインポートされ、エラーが発生した場合に、その可能性のあるエラーがどこで発生するかを少なくとも知ることができます。
CPP
#include> > // Avoid this> using> namespace> std;> > void> foo()> {> >// Inside function> >// Use the import statement inside limited scope> >using> namespace> std;> > >// Proceed with function> }> |
>
モデムとルーターの違い
>
結論。
名前空間から識別子にアクセスするための代替方法について説明しました。どのような場合でも、名前空間全体をソース コードにインポートすることは避けてください。
優れたコーディング手法を習得して開発するには時間がかかる場合がありますが、通常は長期的には報われます。クリーンで曖昧さのない、堅牢でエラーのないコードを書くことは、プログラミング開発者の意図であるはずです。