命名空间范围内使用static关键字无效?

26
namespace N
{
   static int x = 5;
}

在命名空间作用域中声明静态变量有什么重要性/用途?


1
我认为不鼓励使用 static,而应该使用未命名的命名空间。 - ereOn
1
@ereOn:不完全是这样。C++03已经弃用了它的使用,但是C++11已经取消了弃用。为什么?因为它在某些方面很有用。 - Nawaz
6个回答

41

静态变量在命名空间范围(全局或其他)具有内部链接。这意味着它无法从其他翻译单元访问。它是在声明它的翻译单元内部的。


12
这是一个更好的答案,因为它解释了static在命名空间作用域中所起的作用。它不是没有作用,也不是无用的。 - John Dibling

14

附录 D(兼容性特征)[C++03]

D2:在命名空间作用域中声明对象时,使用 static 关键字已被弃用。

请改用未命名的命名空间,如此贴所述。

正如其他人在他们的帖子中提到的那样,static 关键字在 C 和 C++ 中都会为变量/对象提供内部链接。

P.S: 根据最新草案(n3290),该功能已被取消弃用。 在 n3225 中,§7.3.1.1/2 虽然存在,但已被删除线划掉。


+1,此外,虽然没有特别的理由不能使用未命名的命名空间来完成这个任务,但一些编译器对于具有“静态”链接函数(例如在翻译单元中未使用符号时发出警告)提供更多的诊断信息。 - David Rodríguez - dribeas

2
我同意Nawaz的回答:在命名空间中,static关键字并不完全无用,它定义了变量在翻译单元内的内部链接。
例如: header.h
namespace test{
    static int i = 5;//definition is here.And there will be no multiple definition!
    void set_i();
    void print_i();
}

header.cpp

#include "header.h"
#include "iostream"
void test::set_i()
{
    i = 10;
    return;
}

void test:print_i()
{
    using namespace std;
    cout << "print_i is " << i << endl;
    return;
}

main.cpp

#include "header.h"
#include "iostream"
using std::cout;
int main()
{
    test::i = 20;
    test::set_i();
    cout << "i is " << test::i << endl; 
    test::print_i();
    return 0;
}

使用 g++ -std=c++11 header.cpp main.cpp 编译它,你就不会遇到 multiple definition error。如果移除 static 关键字并编译,那么一定会出现 multiple definition error。请务必运行程序并观察结果,你可能会感到惊讶。 static 关键字使得每个包含命名空间声明的接口头文件的 cpp 文件实现单元都有一个内部链接的静态变量副本。因此,即使你在命名空间中定义该变量,如果加了 static 关键字,就不会出现多重定义错误。(对于没有带有 externconst 来定义具有内部链接的变量也是同样的道理,这就是 C++ 中如何丢弃宏定义的。) 因此,“在命名空间中定义的变量隐式为 static”这种说法是错误的,而 static 在命名空间中其实并非完全没用处。由于每个实现单元都有变量的一个副本,因此会消耗空间。
然而,未命名的命名空间可以使其内部的类声明在其他实现单元中无法访问,而 static 关键字则不能“属性”一个类,因此这是未命名的命名空间的一个优势。此外,你可以在嵌套命名空间中使用未命名的命名空间来限制变量的访问。未命名的命名空间是为了保护局部性而设计的,而不是提供接口。

1

C++标准§7.3.1.1/2:

在命名空间作用域中声明对象时,使用static关键字已被弃用(请参见附录D);未命名的命名空间提供了更好的替代方案。

除非未命名的命名空间在未来的标准中提供了更好的替代方案(它将被取消弃用)以实现C兼容性。


4
这个在2011年不是已经取消废弃状态了吗? - user2100815
1
我相信C++0x标准在这种情况下取消了static的弃用,不是吗? - Fred Larson
在我手头的最后一份草稿中(来自2010年3月29日),尽管以修改的形式出现,但这句话仍然存在:单词“objects”已被替换为“variables”。(也许在稍后的草稿中会有变化?) - James Kanze
@James 我记得BS曾经评论过,淘汰是个不好的想法,因为它会破坏C的兼容性。而且我自己一直更喜欢静态的命名空间而不是匿名的命名空间。 - user2100815
1
@Neil 范围不是问题;static 不影响范围。 "类"(即:类的名称和所有成员的名称)具有外部链接,除非它们是局部的(在函数中定义)。因此,如果我在我的翻译单元中定义了 class C { public: C(); };,而你也这样做了,C::C 在两者中都指向同一实体。如果我们都定义它,链接时可能会得到重复定义。(严格来说,这是未定义行为。)而且你无法使 static 应用于一个类;这就是为什么引入了匿名命名空间的原因。 - James Kanze
显示剩余11条评论

0

与在全局命名空间中声明静态变量相同,但仅限于特定命名空间。


0

其他人已经说过了,还有一个微妙之处:static引入了内部链接,而匿名命名空间则没有。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接