《C++之那些年踩过的坑(一)》
C++之那些年踩过的坑(一)
作者:刘俊延(Alinshans)
本系列文章针对我在写C++代码的过程中,尤其是做自己的项目时,踩过的各种坑。以此作为给自己的警惕。
转载请注明原文来自: http://www.cnblogs.com/GodA/p/6501505.html
这一篇就讲点简单的东西,名称空间。
一、谨慎在全局范围使用 using namespace XXX
注意,是在全局范围使用 using namespace XXX,除非写个玩具,否则最好不要这样。之前很喜欢在文件开头就使用 using namespace std,因为可以省很多事。后来我在写 MyTinySTL 这个项目的时候,写测试时为了方便,用了 using namespace std,结果惨不忍睹,大量的名称冲突。当使用 using namepsace xxx 的时候,会把 xxx 这个名称空间里的内容引入到当前空间,如果很不幸,有相同的函数,类等等,就会造成冲突。然而如果碰巧没有冲突,那也只是暂时的,谁知道以后会加入一些什么东西呢?
比如,你写了这样的东西:
#include <iostream>
#include <vector> namespace your
{ template <typename T>
class vector
{
public:
vector() = default;
~vector() = default;
private:
T* data;
}; } using namespace std;
using namespace your; int main()
{
vector<int> v;
}
很明显,这是编译不过的,同时引入了 std 和 your 两个名称空间,且都有一个 vector 模板类,编译器是不知道要使用哪个的。当然,这个太明显了没有人会这么做。但是,如果代码多了呢?文件多了呢?一不小心在哪个地方用了,也不知道会不会 #include 的时候一层一层的也间接的弄了进来。即使你在某个局部的名称空间xxx内声明了 using namespace std,但是也不能保证哪天谁用你的代码,然后为了方便使用你的东西,using namespace xxx,然后又间接引入了一个 std 导致爆炸。
有很多更好的解决方法。比直接在全局使用 using 声明好一点的是,在局部使用,并且只声明需要的部分。比如有时候我们经常在一个函数/作用域内使用 std::cout, std::endl,那么或许可以这样:
void test()
{
using std::cout;
using std::endl; cout << "1+1=" << + << endl;
cout << "1+2=" << + << endl;
cout << "1+3=" << + << endl;
// ...
}
上面这样写当然是没问题了啦,不过我现在习惯,并推崇的还是显式声明,一来这样可以更清晰的知道,用的是哪里来的东西,而且几乎放多久都不会错,二来多敲几个键而已,不是什么麻烦事。以上说了很多,都是以 std 为例,对其它的,也应该保持同样的态度,不禁止,但是要谨慎。不过还是养成好习惯比较好,那么就把 using namespace std; 写成 std::xxx 吧。
放一段 C++ Coding Standards 里面的话:
Summary
Namespace usings are for your convenience, not for you to inflict on others: Never write a using declaration or a using directive before an #include directive.
Corollary: In header files, don’t write namespace-level using directives or using declarations; instead, explicitly namespace-qualify all names. (The second rule follows from the first, because headers can never know what other header #includes might appear after them.)
Discussion
In short: You can and should use namespace using declarations and directives liberally in your implementation files after #include directives and feel good about it. Despite repeated assertions to the contrary, namespace using declarations and directives are not evil and they do not defeat the purpose of namespaces. Rather, they are what make namespaces usable.
在放一句 Google C++ Style Guide 里的一条:
You may not use a using-directive to make all names from a namespace available.
二、关于匿名 namespace
关于 unnamed namespace,cppreference 如是说到:
Its members have potential scope from their point of declaration to the end of the translation unit, and have internal linkage.
也就是说,现在,在匿名空间里的成员,具有内部链接。现在来说,匿名空间跟 static 就没区别了。不过依然要注意,在同一层次中,可以有多个匿名空间,不过这些匿名空间会被整合成一个,所以不能像这样写,会报重定义:
#include <iostream> namespace
{
void foo() { std::cout << "" << "\n"; }
} namespace
{
void foo() { std::cout << "" << "\n"; }
} int main()
{
foo();
}
这很容易理解。在不同空间内的匿名函数,就是不同的啦,比如这样就可以通过了:
#include <iostream> namespace
{
void foo() { std::cout << "" << "\n"; }
} namespace n1
{
namespace
{
void foo() { std::cout << "" << "\n"; }
}
} int main()
{
foo();
n1::foo();
}
在 Google C++ Style Guide 中,这样讲到匿名namespace:
When definitions in a
.cc
file do not need to be referenced outside that file, place them in an unnamed namespace or declare themstatic
. Do not use either of these constructs in.h
files.Use of internal linkage in
.cc
files is encouraged for all code that does not need to be referenced elsewhere. Do not use internal linkage in.h
files.
他们鼓励在实现文件中,把那些不需要外部引用的东西放进匿名空间中。陈硕大大在他的 CppPractice 中,第一个提到的就是慎用匿名空间。我觉得,对于他说的不利之处,现在来看,主要还是是第一点。因为匿名namespace里的东西是匿名的,所以万一以后有一天想引用它了,也说不准。其实还是用个具体名称,也不麻烦。对于那些实现细节,或者不希望暴露的,我喜欢扔进一个 namespace details{} 或者什么 namespace impl {} 里。
今天就先谈这么多。总结一下我自己的观点:
- 使用 using namespace xxx xxx::yyy
- 一般情况下,都使用具名 namespace
《C++之那些年踩过的坑(一)》的更多相关文章
- 简单物联网:外网访问内网路由器下树莓派Flask服务器
最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...
- 利用ssh反向代理以及autossh实现从外网连接内网服务器
前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...
- 外网访问内网Docker容器
外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...
- 外网访问内网SpringBoot
外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...
- 外网访问内网Elasticsearch WEB
外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...
- 怎样从外网访问内网Rails
外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...
- 怎样从外网访问内网Memcached数据库
外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...
- 怎样从外网访问内网CouchDB数据库
外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...
- 怎样从外网访问内网DB2数据库
外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...
- 怎样从外网访问内网OpenLDAP数据库
外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...
随机推荐
- layer子窗口与父窗口传值
layer作为优秀的jquery框架,可以用作弹出组件.日历.分页等,而且实现简单,只有几十k的大小. 此处给出弹出窗口时子窗口与父窗口的传值.js和css这里不展示引入(以下给出目录结构的图片),仅 ...
- jQuery 关于ajaxfileupload.js插件的逐步解析(ajaxfileupload.js第二弹)
如果你看了上一篇<ASP.NET 使用ajaxfileupload.js插件出现上传较大文件失败的解决方法(ajaxfileupload.js第一弹)>的话,应该就知道我是逼不得已要认真学 ...
- ETL第一篇(Kettle Spoon) 初遇
ETL第一篇(Kettle Spoon) 初遇 ETL第二篇 调用webservice 简介 Kettle 是一款国外开源的 ETL 工具,纯 Java 编写,绿色无需安装,数据抽取高效稳定(数据迁移 ...
- mongdb启动报错
2018-08-19T12:25:31.707+0800 I CONTROL [main] Automatically disabling TLS 1.0, to force-enable TLS 1 ...
- java核心技术-多线程基础
进程.线程 进程(Process) 是程序的运行实例.例如,一个运行的 Eclipse 就是一个进程.进程是程序向操作系统申请资源(如内存空间和文件句柄)的基本单位.线程(Thread)是进程中可 ...
- 常见IT英语单词
lable标签,master精通.主人,reference参考,release发布,schema模式,component组件,persistence持久化,generate生成产生,plugin插件, ...
- ES6学习笔记(三)-正则扩展
PS: 前段时间转入有道云笔记,体验非常友好,所以笔记一般记录于云笔记中,每隔一段时间,会整理一下, 发在博客上与大家一起分享,交流和学习. 以下:
- BZOJ4162:shlw loves matrix II
传送门 利用Cayley-Hamilton定理,用插值法求出特征多项式 \(P(x)\) 然后 \(M^n\equiv M^n(mod~P(x))(mod~P(x))\) 然后就多项式快速幂+取模 最 ...
- 51Nod 算法马拉松23 开黑记
惨啊……虽然开了半天黑,但是还是被dalao们踩了…… 第二次开黑,还是被卡在rank20了,我好菜啊……= = 写一写比赛经过吧…… 看到题之后习惯性都打开,A~D看上去似乎并没有什么思路,F应该是 ...
- bootstrap 中的 iCheck 全选反选功能的实现
喜欢bootstrap 风格的同学应该知道,iCheck的样式还是很好看的. 官网: http://www.bootcss.com/p/icheck/ 进入正题,iCheck提供了一些方法,可以进行全 ...