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

Mat*_* M. 84 c++ standards static c++11

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

在n3092,这被弃用了:

附件D.2 [depr.static]
在命名空间范围内声明对象时,不推荐使用static关键字(见3.3.6).

在n3225中,这已被删除.

我能找到唯一一篇文章有些不正式.

它确实强调,为了与C兼容(以及将C程序编译为C++的能力),弃用令人讨厌.但是,直接将C程序编译为C++本身就是一种令人沮丧的经历,所以我不确定它是否值得考虑.

有谁知道为什么它被改变了?

Joh*_*itb 71

C++标准核心语言缺陷报告和接受的问题中,修订版941012.未解释静态 `他们注意到:

虽然7.3.1.1 [namespace.unnamed]声明不推荐使用static关键字来声明命名空间作用域中的变量,因为未命名的命名空间提供了一个更好的选择,但在可预见的将来,该功能不太可能被删除. .

基本上说贬值static并不是真的有意义.它永远不会从C++中删除,它仍然有用,因为如果你只想声明一个带有内部链接的函数或对象,你不需要你需要的未命名命名空间的样板代码.

  • 我喜欢将辅助函数、全局变量等声明为静态并尽可能接近它们的用法。命名空间 { } 语法为此目的是丑陋的,“静态”很好。其他人喜欢将他们所有的助手内容放在文件的顶部。命名空间 {} 语法在那里更有用。所以这真的是一个风格问题。它们最终是等价的。 (3认同)
  • 好吧,似乎弃用会鼓励人们使用未命名的命名空间,这将是一件好事. (2认同)
  • @nbt:因为你不能使用静态符号作为模板参数,并且因为许多新手会发现静态更容易使用,然后未尝试尝试<functional>和<algorithm>等.只是一个快速的想法. (2认同)
  • "因为您不需要使用未命名的命名空间所需的样板代码"?什么是"样板代码"?超越"`namespace {`"和"`}`"的东西? (2认同)
  • @towi 与静态相比,有两个额外的大括号,在许多编码样式中,您将至少编写 3 行代码来缩进声明。 (2认同)
  • @ErikAronesty 如果您在另一个同名文件中有一个“本地类”,那么您将犯 ODR 违规。 (2认同)

cur*_*guy 28

我会尝试回答你的问题,虽然这是一个老问题,但它看起来并不重要(它本身并不是很重要),而且它已经收到了很好的答案.我想回答的原因是,当语言基于现有语言,它与标准进化和语言设计的基本问题有关:何时应该以不兼容的方式弃用,删除或更改语言功能?

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

实际上是联系.

在n3092,这被弃用了:

弃用表示:

  • 意图,以消除在未来的某个功能; 这并不意味着在下一个标准版本中将删除已弃用的功能,或者必须"很快"删除它们,或者根本不删除它们.未弃用的功能可能会在下一个标准版本中删除.
  • 正式试图阻止其使用.

后一点很重要.虽然从来没有一个正式的承诺,你的程序不会被破坏,有时默默地,通过下一个标准,委员会应该尽量避免破坏"合理的"代码.弃用应告诉程序员依赖某些功能是不合理的.

它确实强调,为了与C兼容(以及将C程序编译为C++的能力),弃用令人讨厌.但是,直接将C程序编译为C++本身就是一种令人沮丧的经历,所以我不确定它是否值得考虑.

保留C/C++公共子集非常重要,尤其是对于头文件.当然,static全局声明是带有内部链接的符号声明,这在头文件中不是很有用.

但问题不仅仅是与C的兼容性,它与现有C++的兼容性:有大量现有的有效C++程序使用static全局声明.这段代码不仅正式合法,而且听起来很合理,因为它使用了明确定义的语言功能.

仅仅因为现在有一种"更好的方式"(根据某些人)做某事并不能使程序以旧方式"坏"或"不合理".static在C和C++社区中,可以很好地理解在全局范围内使用关键字声明对象和函数的能力,并且通常使用正确.

与此类似,我不会改变C-风格转换到doublestatic_cast<double>仅仅因为"C风格的转换都是坏的",因为static_cast<double>加零信息和零安全.

这种想法是,每当发明一种新的做事方式时,所有程序员都会急于重写他们现有的明确定义的工作代码,这简直就是疯了.如果你想删除所有继承的C ugliness和问题,你不要改变C++,你发明了一种新的编程语言.半删除一次使用static几乎不会使C++变得不那么丑陋.

代码更改需要一个理由,"旧有坏"绝不是代码更改的理由.

打破语言变化需要非常强有力的理由.使语言变得非常简单,这绝不是破坏性变革的理由.

给出原因static不好的原因只是非常弱,并且甚至不清楚为什么不同时弃用对象和函数声明 - 给它们不同的处理几乎不会使C++更简单或更正交.

所以,真的,这是一个悲伤的故事.不是因为它具有实际后果:它实际上没有实际后果.但是因为它显示出ISO委员会明显缺乏常识.

  • 正如你自己指出的那样,弃用它的目的是阻止它的使用.然而,你没有提出阻止其使用的论据是错误的.我当然希望没有人鼓励人们在匿名命名空间上使用命名空间范围的静态声明.除非他们特别需要交叉编译C. (4认同)
  • 整个语言将"有一天消失".我们不赞成使用C++. (4认同)
  • 我不太关心使用全局范围`static` 或匿名命名空间的人,我也不鼓励或劝阻。我的观点是,如果你真的想阻止人们使用匿名命名空间,你必须给他们很好的论据。在实践中,我相信在大多数实现中,在未命名命名空间中声明的实体是使用随机名称导出的符号,从而增加了导出表。声明为“静态”、OTOH 的实体不会以任何方式导出。因此,根据观察结果,许多人选择使用“静态”。 (3认同)
  • “_正如你自己指出的那样,弃用它的目的是阻止它的使用。_” 阻止它使用的重点是它可能有一天会消失。我的观点是命名空间范围的 `static` 永远不会消失,所以弃用它是错误的。“_然而,你没有提出不鼓励使用它是错误的论点。_”我没有看到任何令人信服的论据表明使用命名空间范围的 `static` 是“错误的”。仅仅为了阻止它的使用而弃用它是错误的,因为没有人真正相信它会消失,而且因为它不能让人们相信使用它是“错误的”。 (3认同)
  • *`static_cast&lt;double&gt;` 添加了零信息和零安全性* - 从语言解析器的角度来看,它确实添加了零信息。从编辑器中的 Ctrl-F 视图或 grep 视图来看,它添加了一种定位所有演员表以进行审核/审查的方法。但鉴于 libclang 等静态代码分析框架的可用性,可以轻松定位任何此类构造,针对此类 C 风格强制转换的警告确实已经深入人心。 (3认同)
  • “_我当然希望没有人鼓励人们在匿名名称空间上使用名称空间范围的静态声明。_”有些人认为 `static` 更好,并鼓励在匿名名称空间上使用它。我的观点并不是说任何一个都比另一个更好;我的观点是 1) 没有任何功能(`static`,匿名命名空间)是“错误的”。2) 弃用一个有用的、定义明确的、广泛使用的特性,但它不会——永远——是错误的。这样做会降低 C++ 委员会的可信度(而且已经很低了)。 (2认同)
  • “同样,我不会仅仅因为“C 风格转换很糟糕”而将 C 风格转换从 double 更改为 static_cast&lt;double&gt;,因为 static_cast&lt;double&gt; 增加了零信息和零安全性。” 我与许多软件工程师进行了永恒的斗争,他们不断抱怨我对 C 风格的随意使用,从一种原始类型转换为另一种原始类型。 (2认同)
  • 这与基元无关。原始类型转换始终是一个安全的操作,在原始类型转换时,静态类型转换无法为您做任何事情,也不会检查是否可以将 flaot 转换为 int,反之亦然。 (2认同)
  • @sigma 是的,C 风格的 ptr 转换何时被解释为“dynamic_cast”?从来不明显。“dynamic_cast”何时与整数和 fp 等数字的转换有任何关系?再也不。因此,虽然您关于“新风格”(它们不再是“新”)的强制转换更加明确和更具可读性(通过使内容“_对其他人来说非常清晰_”)的观点广受好评,但它们主要适用于涉及 ptr 的*强制转换*在某一点。**它们不适用于以任何方式转换为`double`。**您不能只使用有关 ptr 转换的参数并将其“转置”为其他类型。 (2认同)
  • @Makogan:如果它是您控制的某个局部变量,我同意,但假设该变量后来更改为指针:静态强制转换现在是非法的,但 C 强制转换将继续编译。不太可能,但安全性稍差。curlyguy:确实从来没有,但它只是让太多的事情太过安静。我的主要观点是,C++ 转换不仅向编译器显示了潜在有用的信息,而且还向代码的其他读者/维护者显示了潜在有用的信息,这是 C 语法无法表达的。也就是说,你完全正确,“(双)”铸造是相当良性的,我不会因为你这样做而严厉批评你。 (2认同)

Max*_*kin 12

是否弃用,删除此语言功能会破坏现有代码并使人烦恼.

整个静态弃用的东西只是一厢情愿的想法,"匿名命名空间优于静态","引用是更好的指针".大声笑.

  • “参考是更好的指针”?不,智能指针是更智能的指针。您不能对从堆、错误、自由存储分配的内存使用引用。 (3认同)
  • 对不起,我忘了带着讽刺的笑容结束它. (2认同)
  • @Dan:这正是这个答案所说的:沿着类似错误思路的“一厢情愿”。未命名的命名空间是一个重要的特性,就像 global-scope-static 一样,尽管原因略有不同,即使它们在适用性上有一些重叠。 (2认同)
  • @DanBreslau:`char* foo = new char; char&amp; ref = *foo;` 仅仅因为您最初获得了一个指针,并不能说明您使用引用的能力。 (2认同)