当前位置: 首页 > news >正文

[转载]我再也不想在任何头文件中看到“using namespace xxx;”了

原文

====

在这里,我毫不回避地说了这句话。

作为一个开发者/团队领导者,我经常会去招聘新的项目成员,有时候也帮助其他组的人来面试应聘者。作为应聘流程之一,我经常要求应聘者写一些代码,因此我检查过相当多的代码。在最近提交的C++代码中,我注意到一个趋势,在任何头文件中,我总是能看到以下代码:

using namespace std;

如果我用我们的代码检查系统(在实践中我十分推荐这个系统)来检验代码,以上那行代码经常会跟着一句评论“Timo不会这样写的”。他们说得很对,我确实不会这么写。

那么,为什么我说服了很多C++教材(也许并不是什么好事),让他们认为使用上面那段代码是非常坏的方式?让我们先来看看上面那段代码做了什么。总的来说,它把命名空间“std”以内的所有内容(或者其他由作者用using调用命名空间)无一例外的引入了目前的命名空间中。请注意我说的“所有内容”,并不是一两个你想用的类\类型\模板。在一段代码的开头引入命名空间的原因则是加强程序模块化,和减少命名冲突。大体上,它允许你可以写类似下面的那段代码,并且保证编译器可以选择正确的实现:

std::vector<std::string> names;
my_cool_reimplementation::vector<our_internal_stuff::string> othernames;

现在,假定我们正在尝试减少代码输入,并且在以上代码中使用using声明(或者更糟糕的,两个命名空间都声明了),按照如下代码来实现:

vector<string> names;
vector<our_internal_stuff::string> othernames;

如果这段代码的作者很幸运的话,编译器会选择vector的正确实现,或者至少在最初的阶段会这么做。但是过了一段时间,你会碰到一些很奇怪的编译器错误。幸运的话,你能找到这些错误的原因——我曾经遇到过类似问题,我花费了好几天才能找到这类问题的原因。该死,它们会浪费你很多的时间,仅仅因为你为了想少打5个字符的代码。

并且,如果你把using声明用在了头文件中,你会让这类问题更加恶化,因为命名冲突问题早晚都会在一个调用关系非常非常远的模块中神不知鬼不觉的出现,而你可能需要查三层调用才可以找到原因所在,一个头文件包含了另一个直接使用using声明的头文件可以导致命名空间被立刻污染掉,任何一个使用命名空间的文件如果使用了std命名空间的内容,都会导致这类问题。

那么,为什么你能在很多教科书中看到它们使用using namespace std?我的理论是,它确实会帮助改善整本书的排版,并且能减少一些视觉的混乱。在一本纸质书中,你只有很有限的空间来写文字,因此你必须最大限度的利用它,加之书中的代码例子通常都很简单。但另一方面,不同的命名空间限定符会带来了很多视觉混乱,这会让读者很难从上下文判断作者的意图。当你想在这个时代写一些有效率的代码的时候,以上两点都不完全对,现在的编译器大多数能每行处理60-80个单词(你可以试试,这可以的)。因此,不要乱引入命名空间。

如果你非常明确的想在一个头文件中使用using声明,应该怎么做?我们有其他途径可以减少不得不用using声明的情况——你可以用以下其中一种,或则多种方式的组合。

首先,你只需使用typedef。我会建议你使用这种方法,即使我并不经常遵循我自己的建议,我也认为无论如何这都是一个在实际应用中很好的方法。实际上,使用typedef有两个好处——他让一个类型名可读性增加,如果你选择了一个很好的名字,它可以让作者的意图更加显而易见。比较一下如下的声明方式:

std::map<std::string, long> clientLocations;
typedef std::map<std::string, long> ClientNameToZip;
ClientNameToZip clientLocations;

第二个声明——即使它被展开为两行——也比第一个声明更加直观,同时,它也避免了命名空间模糊化。

另外一个选择则是用两种方法来限制using声明的作用域——仅仅是你想用的那个“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的作用域限制到需要使用它的代码中,而不是把它放到代码的公共空间中。你的工程越大,确保模块化,和最小化不可预料的负面影响就显得越发重要。

原文:I don’t want to see another “using namespace xxx;” in a header file ever again

转载于:https://www.cnblogs.com/jffifa/archive/2013/01/17/2864440.html

相关文章:

  • Mybatis架构设计及源码分析-SqlSession
  • C# 禁止windows程序重复运行的两种基本方法
  • 代码动态设置edittext输入类型为密码类型
  • 用ASDF来组织Lisp程序编译和加载
  • TensorFlow与OpenCV,读取图片,进行简单操作并显示
  • 移动终端开发必备知识
  • MAC配置环境变量
  • oracle的nvl和sql server的isnull
  • UTC时间与当地时间的转换关系?
  • oracle分页查询
  • 做项目学习Django2.0开发
  • [转]虚拟机下Ubuntu共享主机文件(Ubuntu、VMware、共享)
  • js中clientHeight,offsetHeight,scrollHeight的区别
  • Range Slider With Progress
  • nohup命令
  • 5、React组件事件详解
  • Centos6.8 使用rpm安装mysql5.7
  • Java比较器对数组,集合排序
  • Linux快速复制或删除大量小文件
  • Map集合、散列表、红黑树介绍
  • oschina
  • Redis学习笔记 - pipline(流水线、管道)
  • webpack+react项目初体验——记录我的webpack环境配置
  • Zepto.js源码学习之二
  • 机器学习中为什么要做归一化normalization
  • 前嗅ForeSpider采集配置界面介绍
  • 如何利用MongoDB打造TOP榜小程序
  • 想使用 MongoDB ,你应该了解这8个方面!
  • 由插件封装引出的一丢丢思考
  • 怎么将电脑中的声音录制成WAV格式
  • 国内开源镜像站点
  • 如何用纯 CSS 创作一个货车 loader
  • 说说我为什么看好Spring Cloud Alibaba
  • ​LeetCode解法汇总1410. HTML 实体解析器
  • #宝哥教你#查看jquery绑定的事件函数
  • (1)(1.13) SiK无线电高级配置(五)
  • (4) openssl rsa/pkey(查看私钥、从私钥中提取公钥、查看公钥)
  • (6)STL算法之转换
  • (function(){})()的分步解析
  • (多级缓存)多级缓存
  • (七)c52学习之旅-中断
  • (三)Pytorch快速搭建卷积神经网络模型实现手写数字识别(代码+详细注解)
  • (三十五)大数据实战——Superset可视化平台搭建
  • (已解决)vue+element-ui实现个人中心,仿照原神
  • (转)程序员技术练级攻略
  • *p=a是把a的值赋给p,p=a是把a的地址赋给p。
  • .gitignore
  • .NET Compact Framework 多线程环境下的UI异步刷新
  • .NET Core WebAPI中封装Swagger配置
  • .net 调用php,php 调用.net com组件 --
  • .NET/ASP.NETMVC 深入剖析 Model元数据、HtmlHelper、自定义模板、模板的装饰者模式(二)...
  • .NetCore Flurl.Http 升级到4.0后 https 无法建立SSL连接
  • .NET面试题(二)
  • .NET企业级应用架构设计系列之开场白
  • .Net小白的大学四年,内含面经