为什么在C++中将"使用命名空间"包含在头文件中是一个坏主意?

use*_*338 26 c++ namespaces global-namespace

在阅读Bruce Eckel关于命名空间的"Thinking in C++"时,我遇到了以下声明:

但是,您几乎从未在头文件中看到using指令(至少不在范围之外).原因是using指令消除了对该特定命名空间的保护,并且效果持续到当前编译单元结束.如果在头文件中放置using指令(在作用域之外),则意味着在包含此头文件的任何文件中都会发生"名称空间保护"丢失,这通常意味着其他头文件.

您是否愿意用一些简单的例子来帮助我理解上述陈述?

Ton*_*roy 31

考虑这个程序:

line#
    1 #include <string>                                                               
    2                                                                                 
    3 using namespace std;                                                            
    4                                                                                 
    5 struct string { const char* p; };  // Beware: another string!
    6                                                                                 
    7 int main()                                                                      
    8 {                                                                               
    9     string x; // Error: ambiguous - which string is wanted?
   10 }
Run Code Online (Sandbox Code Playgroud)

如果您尝试编译它,您将看到错误:

g++     using.cc   -o using
using.cc: In function `int main()':
using.cc:9: error: use of `string' is ambiguous
using.cc:5: error:   first declared as `struct string' here
/usr/lib/gcc/i386-redhat-linux/3.4.6/../../../../include/c++/3.4.6/bits/stringfwd.h:60: error:
   also declared as `typedef struct std::basic_string<char, std::char_traits<char>, std::allocator<char> > std::string' here
using.cc:9: error: `string' was not declared in this scope
using.cc:9: error: expected `;' before "x"
Run Code Online (Sandbox Code Playgroud)

这里的问题是,当main()指定时string x;,编译器不确定是否需要用户定义::string或包含std::string.

现在想象一下你把程序的顶部...第1行到第5行 - 直到并包括struct string......然后把它放到你#include之前的头文件中main().没有任何变化:你仍然有错误.因此,就像独立程序一样,带有using语句的头文件可能会给包含它们的其他代码带来麻烦,使得它们的一些语句不明确.

它可能是一个更大的痛苦,因为标题可以直接或间接地包含在任意大量的依赖代码中,并且...

  • using从标题中删除语句,或
  • 更改内容<string>或影响的任何其他标题std::

...可能会破坏包含有问题标题的代码.任何一个问题都可能使相关代码无法编译,甚至在尝试进行另一次编译之前甚至都不会发现问题.此外,由于该using声明而受苦的人可能没有文件系统/代码库权限,公司权限等using从头中删除该语句,也不能修复其他受影响的客户端代码.

也就是说,如果一个头只在一个类或函数中有"使用",那么对该范围之外的代码没有任何影响,因此对std ::的更改的潜在影响会大大减少.


Fre*_*Foo 16

如果标头包含using namespace std,则来自该命名空间的所有内容都将在包含标头的每个模块中添加全局命名空间.

这意味着您永远不能声明函数或定义具有相同名称的类(以及函数的兼容参数)作为std任何这些模块中的全局命名空间中的函数/类.

  • “你永远不能声明一个函数或定义一个同名的类”——你实际上可以,只是调用者必须消除用法歧义,这样做全局版本优先匹配`::identifier`,而“used”版本必须像`::std::identifier`一样访问。有趣的是,如果没有歧义,显式的 `::identifier` 确实会找到“使用过的”版本,所以你的“来自该命名空间的所有内容都被添加到 [到] 全局”是正确的观点......它不仅仅是一个没有 `::` 前缀的标识符的辅助隐式搜索位置.... (2认同)

小智 5

复制"C++ Primer,第五版"中的以下段落:

标题内的代码通常不应使用using声明.原因是标题的内容被复制到包含程序的文本中.如果标头具有using声明,那么包含该标头的每个程序都会使用声明获得相同的结果.因此,不打算使用指定库名的程序可能会遇到意外的名称冲突.