静态关键字的弃用...不再使用?

104
在C++中,可以在翻译单元内使用static关键字来影响符号(变量或函数声明)的可见性。
在n3092中,这被弃用:

Annex D.2 [depr.static]
在命名空间范围内声明对象时,使用static关键字已被弃用(参见3.3.6)。

在n3225中,已经删除了这个功能。 我找到的唯一一篇文章有些非正式。
它确实强调,为了与C兼容(以及将C程序编译为C ++的能力),弃用是令人讨厌的。然而,直接将C程序编译为C ++可能已经是一种令人沮丧的体验,因此我不确定是否值得考虑。
有人知道为什么要更改吗?

5
你在 C 中声明命名空间作用域的对象吗? - Etienne de Martel
2
这也为C++委员会提供了在下一个标准版本中取消某些不推荐使用的东西的机会 :-) - James McNellis
@MartinBa:啊!好的,我以为你想问一些问题,然后不知怎么就按下了回车键,但是一个小时过去了,我很惊讶没有看到问题的出现 :) - Matthieu M.
@MatthieuM.:在上面的帖子中,有关于你的问题的客观答案,告诉了所有static在未命名命名空间不起作用的地方;而这里的答案似乎主要基于个人意见。 - legends2k
显示剩余4条评论
3个回答

82
C++标准核心语言缺陷报告和已接受问题,修订941012. 取消对static的弃用中指出:
尽管7.3.1.1 [namespace.unnamed]规定,在命名空间范围内声明变量使用static关键字是被弃用的,因为未命名的命名空间提供了更好的选择,但这个特性不太可能在可预见的未来被删除。
基本上这意味着取消对static的弃用没有什么意义。它永远不会从C++中移除。它仍然很有用,因为如果你只想声明一个具有内部链接的函数或对象,就不需要使用未命名的namespace时所需的样板代码。

4
看起来,弃用会鼓励人们使用未命名的命名空间,这是一件好事。 - sbi
5
“因为你不需要使用未命名命名空间所需的样板代码”中的“样板代码”是指除了“namespace {”和“}”以外的其他代码。 - towi
3
与静态相比,动态需要多写两个大括号,并且在许多编码风格中,您需要至少编写三行代码来缩进声明。 - Johannes Schaub - litb
5
我喜欢将辅助函数、全局变量等声明为静态的,并尽可能靠近它们的使用位置。对于这个目的,命名空间{ }语法不太美观,“static”就足够了。其他人喜欢把所有的辅助内容都放在文件的顶部。在那里,命名空间{}语法更有用。因此,这实际上是一个风格问题。它们最终都是等效的。 - Erik Aronesty
3
如果你在另一个文件中有一个同名的“局部类”,那么你将违反ODR(一次定义规则)的规定。 - L. F.
显示剩余5条评论

36

虽然这是一个旧问题,看起来并不是非常重要(实际上本身并不是非常重要),而且它已经得到了相当不错的答案,但我会尝试回答,因为它涉及到标准演变和基于现有语言设计语言时的基本问题:何时应该废弃、删除或以不兼容的方式更改语言特性?

在C++中,可以在翻译单元内使用static关键字来影响符号的可见性(无论是变量还是函数声明)。

实际上是链接性。

在n3092中,这被弃用了:

弃用表示:

  • 有意在未来删除某些功能;这并不意味着弃用的功能将在下一个标准修订中被删除,或者它们必须很快或根本不被删除。而非弃用的功能可能会在下一个标准修订中被删除。
  • 正式尝试阻止其使用

后一点很重要。尽管从来没有正式承诺您的程序不会被下一个标准打破,有时甚至是悄无声息的,但委员会应该尽量避免打破“合理”的代码。弃用应该告诉程序员:依赖某些功能是不合理的

它确实强调了与C的兼容性(以及将C程序编译为C++的能力)的问题,这种弃用很让人恼火。然而,直接将C程序作为C++编译可能已经是一种令人沮丧的体验,因此我不确定它是否值得考虑。

保留C/C++公共子集特别重要,特别是对于头文件。当然,全局static声明是具有内部链接的符号声明,在头文件中并不非常有用。

但问题并不仅仅是与C的兼容性,也涉及到与现有的C++代码的兼容性:存在着大量使用static全局声明的有效C++程序。这些代码不仅在形式上合法,而且还是正确的,因为它们使用了一种明确定义的语言特性,按照其预期的方式使用。

仅仅因为现在有一种“更好的”方法(根据某些人的说法),并不意味着用旧方法编写的程序“不好”或“不合理”。在C和C++社区中,使用static关键字在全局范围内声明对象和函数的能力是被很好理解的,而且通常被正确使用。

类似地,我不会将C风格的强制类型转换更改为static_cast<double>,只是因为“C风格的强制类型转换是不好的”,因为static_cast<double>没有增加任何信息或安全性。

每当发明一种新方法来做事情时,所有程序员都会匆忙地重写他们现有的、经过良好定义的工作代码的想法是完全不切实际的。如果您想消除所有继承自C的丑陋和问题,您不应该改变C++,而是应该发明一种新的编程语言。 半删除static的一个用法并不能使C++不那么C丑陋。

代码更改需要有理由,只是因为“旧的不好”从来都不是代码更改的理由。
破坏性的语言更改需要非常强的理由。让语言变得稍微简单一点从来不是对破坏性变更的正当理由。
给出的static不好的原因非常薄弱,甚至不清楚为什么对象和函数声明不能一起被弃用——这样做并没有使C++更简单或更正交。
因此,真正令人悲哀的是这个故事。不是因为它产生了什么实际后果:它完全没有实际后果。而是因为它显示了ISO委员会缺乏常识。

5
正如你所指出的,废弃它的目的是为了阻止其使用。然而你并没有提出任何反对阻止使用的论据。我当然希望没有人鼓励人们使用命名空间作用域的静态声明来代替匿名命名空间,除非他们特别需要跨编译C。 - Nicol Bolas
4
我并不特别在乎人们使用全局作用域的static或匿名命名空间,我既不鼓励也不阻止。我的观点是,如果你真的想要阻止人们使用匿名命名空间,你必须给他们一个好的理由。实际上,我认为在大多数实现中,声明在未命名命名空间中的实体是以随机名称导出的符号,因此会增加导出表的大小。而声明为static的实体则以任何方式都不会被导出。因此,许多人根据这个观察结果选择使用static - curiousguy
4
正如您所指出的,废弃它的目的是为了阻止其使用。阻止其使用的目的是为了某一天它可能会消失。我的观点是,命名空间范围内的static永远不会消失,因此废弃它是错误的。然而,您没有提出阻止其使用是错误的论点。我没有看到任何有力的论据表明在命名空间范围内使用static是“错误”的。仅仅为了防止使用而将其废弃是错误的,因为没有人真正相信它会消失,并且因为这并不能说服人们使用它是“错误”的。 - curiousguy
8
整个语言有一天会“消失”。让我们弃用C++。 - Lightness Races in Orbit
3
@sigma,当 C 风格的指针转换被解释为 dynamic_cast 时,何时发生过?显然从来没有。而将 dynamic_cast 与像整数和浮点数之类的数字进行转换相关联的时间是什么时候呢?同样也是从未有过。因此,虽然您提到关于新风格(它们现在不再是“新的”)转换更加明确和易读(通过使“对其他人明显清晰”),这一点很受欢迎,但它们主要适用于涉及某个指针的转换。它们在任何方式下都不适用于将类型转换为 double。您不能只是使用有关指针转换的论点并将其“转换”为其他类型。 - curiousguy
显示剩余20条评论

16

无论是否被弃用,删除这种语言特性都会破坏现有的代码并使人感到烦恼。

整个静态弃用的事情只是一厢情愿的想法,类似于“匿名命名空间比静态更好”和“引用比指针更好”。笑。


3
“References are better pointers”? 不,智能指针才是更聪明的指针。你不能用引用来处理从堆(free store)上分配的内存。 - Dan Breslau
4
抱歉,我忘记在结尾加上一个讽刺的笑脸了。 - Maxim Egorushkin
3
@Dan:这正是这个答案所说的:“一厢情愿”的思维方式。未命名的命名空间和全局作用域静态变量一样,都是一个重要的特性,尽管它们的适用范围略有不同,并且尽管它们在适用性上有些重叠。 - Fred Nurk
2
@DanBreslau: char* foo = new char; char& ref = *foo; 刚因为你最初得到一个指针,并不代表你就能够使用引用。 - Lightness Races in Orbit
重点(可以这么说)是引用始终依赖于另一个变量;您无法使用引用变量替换指针。(实际上,我怀疑您可能可以,但这需要一些极其丑陋的黑客技巧,可能取决于实现。) - Dan Breslau
显示剩余5条评论

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