现代C++中的全局变量

3
创建一个所有成员(属性、函数)都是静态的类有什么(客观的)缺点?特别是与使用命名空间相比?或者你更喜欢创建全局变量/函数?
我喜欢创建静态属性,因为我认为它们更“整洁”。 (我知道它们来自哪里等等。)我对命名空间不太熟悉。而且我对全局变量一点也不舒服,因为我不是很熟悉C关键字,如extern和static。
此外,如果我们考虑类:
class MyStaticClass
{
    private:

        static int x;
        static double y;

    public:

        static float s;
        static double weatherForecast(unsigned int, char);
};

和命名空间

namespace MyNamespace
{
    int x;
    double y;
    float s;
    double weatherForecast(unsigned int, char);
}
  1. 在调用 MyStaticClass::weatherForecast 和调用 MyNamespace::weatherForecast 之间,性能方面有区别吗?

  2. 在读取/写入 MyStaticClass::s 和读取/写入 MyNamespace::s 之间,性能方面有区别吗?

  3. 如果使用类而不是基本类型,上述问题的任何答案是否会改变?


3
"你是想创建一个命名空间吗?" 我认为这是今天通常公认的最佳实践。但这可能只是一种观点。 - πάντα ῥεῖ
2
为什么需要它们?一组常量吗?+ https://isocpp.org/wiki/faq/coding-standards#global-vars - Dmitry Ledentsov
https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables,这可能会很有用。 - 88877
4
“谷歌代码风格指南”是基于谷歌长期的代码积累而制定的,对于编写新代码并不是很有用。 - Bo Persson
抱歉问题不好,感谢@MSalters指正。 - Pippin
显示剩余3条评论
1个回答

9
这是一个关于创建类的问题,所有成员(属性、函数)是否都应该是静态的?这被称为“单例模式”,具体情况要看情况而定。使用静态函数的类可以作为模板参数,而命名空间则不行。另一方面,命名空间允许进行参数相关查找,而类则不太行。有些东西确实是全局的,比如标准流、Logger对象、事件循环引擎(线程特定全局)。例如,将Logger对象在每次调用中传递或将其存储为成员变量的代码比必要的复杂。
经常有人错误地认为跨翻译单元的动态初始化顺序是未定义的,因此他们过度使用单例模式而不是普通全局变量来确保单例对象在第一次使用之前被初始化。然而,有一种可移植的技术称为 Schwarz Counter,用于初始化标准流(std::cout和朋友们),它确保这些全局变量在main进入之前甚至在第一次使用之前就被初始化了。

您更新的问题的答案:不,不,不。


1
特别满意于单例模式的揭穿。 - SergeyA
我最近读到,实际上,在某些情况下,Schwarz计数器是一种不被赞同的技术。例如,在LLVM项目编码标准http://llvm.org/docs/CodingStandards.html中,他们写道:“禁止在库文件中使用#include <iostream>,因为许多常见的实现会透明地将静态构造函数注入到包含它的每个翻译单元中。”问题在于所有这些静态初始化都会导致可测量且不必要的程序启动成本,对于每个链接到llvm的程序都是如此。 - Chris Beck
@ChrisBeck,我想知道有哪个C++库不使用Schwarz Counter来初始化std::cout和相关函数? - Maxim Egorushkin
@Maxim 没错,你说的很对(关于运行时间与启动时间)。我也不知道他们所指的C++库是哪一个,它没有使用这种技术来处理 iostream - Chris Beck
2
@MaximEgorushkin,跨编译单元静态对象的初始化顺序实际上并没有被很好地定义。这甚至在您链接到的 Schwartz Counter 的动机中都有说明。对于具有非平凡初始化的纯全局变量要保持警惕是有道理的。 - Danra
显示剩余2条评论

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