[C++]私はもうどのヘッダファイルにもusing namespace xxxという文を見たくありません(訳)

3230 ワード

原文の転送:I don’t want to see another“using namespace xxx;”in a header file ever again
 
ここで、私は少しも回避せずにこの言葉を言った.
開発者/チームリーダーとして、私はいつも新しいプロジェクトメンバーを募集し、時には他のグループの人を助けて応募者を面接します.応募プロセスの1つとして、私はよく応募者にコードを書くように要求しているので、かなりのコードをチェックしました.最近提出されたC++コードでは、どのヘッダファイルでも次のコードが常に表示される傾向に気づきました.
using namespace std;
私たちのコードチェックシステム(実際にはこのシステムを非常に推奨しています)でコードをチェックすると、上記の行のコードには「Timoはそうは書かない」というコメントがついてくることが多い.彼らの言うことは正しいが,私は確かにそうは書かない.
では、なぜ私は多くのC++教材(いいことではないかもしれません)を説得して、上のコードを使うのは非常に悪い方法だと思っていますか?まず、上のコードが何をしたか見てみましょう.総じて、ネーミングスペース「std」内のすべてのコンテンツ(または他の著者がusingでネーミングスペースを呼び出す)を、現在のネーミングスペースに例外なく導入した.私が言った「すべての内容」は、あなたが使いたいクラスタイプテンプレートの1つや2つではありません.コードの先頭にネーミングスペースを導入する理由は、プログラムのモジュール化を強化し、ネーミング競合を減らすことです.基本的には、次のようなコードを書くことができ、コンパイラが正しい実装を選択できることを保証します.
std::vector<std::string> names;
my_cool_reimplementation::vector<our_internal_stuff::string> othernames;

次に、コード入力を減らし、上記のコードでusing宣言(またはさらに悪いことに、2つのネーミングスペースが宣言された)を使用して、次のコードに従って実現しようとしていると仮定します.
vector<string> names;
vector<our_internal_stuff::string> othernames;

このコードの著者が幸運であれば、コンパイラはvectorの正確な実装を選択するか、少なくとも最初の段階でそうします.しかし、しばらくすると、奇妙なコンパイラのエラーに遭遇します.幸いなことに、あなたはこれらの間違いの原因を見つけることができます.私はこのような問題に遭遇したことがあります.私は何日もかけてこのような問題の原因を見つけることができました.5文字のコードを少なくしたいから、多くの時間を無駄にします.
さらに、using宣言をヘッダファイルに使用すると、ネーミング競合の問題はいずれも呼び出し関係が非常に遠いモジュールで知らず知らずのうちに発生し、3層呼び出しを調べて原因を見つける必要がある可能性があります.1つのヘッダファイルにusing宣言を直接使用する別のヘッダファイルが含まれていると、ネーミングスペースがすぐに汚染され、いずれかのネーミングスペースを使用するファイルがstdネーミングスペースの内容を使用すると、このような問題が発生します.
では、なぜ多くの教科書でusing namespace stdを使っているのを見ることができますか?私の理論は、本全体のレイアウトを改善し、視覚的な混乱を減らすのに役立つということです.1冊の紙の本の中で、あなたは文字を書くのに限られた空間しかありません.そのため、それを最大限に利用しなければなりません.加えて、本のコードの例は通常簡単です.しかし一方で,異なるネーミング空間限定子は多くの視覚的混乱をもたらし,読者が文脈から著者の意図を判断することは困難である.この時代に効率的なコードを書きたいときは、上記の2つの点が完全に正しいわけではありません.現在のコンパイラの多くは、1行あたり60~80個の単語を処理することができます(試してみてください.これはできます).そのため、ネーミングスペースをむやみに導入しないでください.
ヘッダーファイルでusing宣言を使用したい場合は、どうすればいいですか?他の方法では、usingで宣言しなければならない状況を減らすことができます.以下のいずれか、または複数の方法の組み合わせを使用することができます.
まずtypedefを使うだけです私はあなたにこの方法を使うことを提案します.たとえ私がいつも自分の提案に従っていなくても、どうしてもこれは実際の応用の中で良い方法だと思います.実際、typedefを使用するには2つのメリットがあります.彼はタイプ名の可読性を増加させ、良い名前を選択すれば、著者の意図をより明らかにすることができます.次の宣言を比較します.
std::map<std::string, long> clientLocations;
typedef std::map<std::string, long> ClientNameToZip;
ClientNameToZip clientLocations;
2番目の宣言-2行に展開されても-1番目の宣言よりも直感的であり、ネーミングスペースの曖昧化も回避される.
もう1つの選択肢は、using宣言の役割ドメインを2つの方法で制限することです.たとえば、あなたが使用したい「using」記号だけです.
using std::string;
ただし、この声明を頭のファイルに捨てるのは、「using namespace」を使用するのと同じくらい悪いので、役割ドメインを使用して可視性を制限し、あなたのusing声明が本当に最初にusing声明をした場所でしか有効でないことを確認する必要があります.たとえば、クラス宣言の役割ドメインを次のように制限できます.
namespace bar
{
  struct zzz
  {
    …
  };
}
class foo
{
  using namespace bar;
  zzz m_snooze; // Pulls in bar::zzz  };
または、usingの役割ドメインを直接関数に制限することができます.たとえば、次のようにします.
void temp ()
{
  using namespace std;
  string test = "fooBar";
}
いずれの方法でも、コードの共通空間に置くのではなく、usingの役割ドメインを使用する必要があるコードに制限することができます.あなたのプロジェクトが大きいほど、モジュール化を確保し、予想できない負の影響を最小限に抑えることが重要になります.