未命名命名空间中的全局非静态变量

3

我找不到一个关于未命名命名空间中全局非静态变量的好解释。我尽可能避免使用全局变量。在这种情况下,我只是从纯理论的角度来看行为。

假设以下代码:

在a.h中:

namespace ai {
  class Widget {
    void DoSomething(int param);
  };
}

在 a.cc 文件中。
namespace {
  int x;
  void Helper() {
  }
}

namespace ai {
  void Widget::DoSomething(int param) {
    x = param;
    Helper();
  }
}
  1. 如果我创建两个相同类Widget的实例,它们会共享变量x吗?

  2. 如果类实例在同一线程或不同线程上,以上行为是否相同?

  3. 如果变量x是自定义类型而不是内置类型呢?

  4. 变量x何时构造,何时销毁?

  5. sizeof(Widget)和这样的变量之间有什么关系吗?

  6. C ++标准中定义了哪些方面,哪些方面没有定义?

还有其他需要考虑的因素吗?也许有人可以提供好的书籍参考(例如“Effective C ++..”),以便深入了解更多?

3个回答

6
如果我创建两个相同类的Widget实例,这两个实例是否共享同一个变量x?
是的。它是全局变量,每个进程只能有一个。
如果类实例在同一个线程中与不同线程中,上述行为是否相同?
全局变量是针对整个进程而言的(而非针对线程)。
如果变量x不是内置类型而是自定义类型,会发生什么?
没有关系。(幸运的是,在C++中内置类型和UDT之间的差异很小。)
在何时构造变量x?何时销毁?
在调用main()之前构造,在之后销毁。跨多个翻译单元的全局变量构造顺序未定义。在同一TU中,它是定义的顺序。(还是声明?我忘了。)销毁的顺序是明确定义的,与构造顺序相反。
sizeof(Widget)和这些变量之间是否有任何关系?
为什么类X和不同类型的变量Y之间会有关系?
C ++标准定义了哪些方面,哪些方面没有定义?
基本上,匿名命名空间中的全局变量是普通的全局变量。唯一的区别是它属于一个你无法拼写且独特于其翻译单元的“有趣”名称的命名空间。

@sbi:许多人似乎认为对象的大小与其拥有/使用的方法/静态属性数量之间应该存在关系。我有时会想,这是否是动态语言的影响,引入了方法的混淆,并随着时间的推移而波及到其他领域。 - Matthieu M.
@Matthieu:即使如此,类Widget的大小如何与全局int变量相关? - sbi
@sbi:我不知道,就好像人们期望在对象级别存储指针或其他东西,因为如果它使用它而我没有将其作为参数传递,它需要引用它...是吗? - Matthieu M.
@Matthieu:关于大小的问题,只有在答案是未命名命名空间中的全局非静态变量在类实例中某种方式上而不是进程范围内时,才实际出现。我在提问时并不知道答案。所以现在我同意sizeof部分与问题无关。有一点令人困惑的是,对于全局变量,static关键字没有任何意义。 - drumsta
@kriau:static 的作用(至少对于全局变量而言,static 还有很多其他含义)是修改变量的链接方式,使其仅在其翻译单元内可见(“内部链接”)。这曾经是为了防止与其他全局变量发生名称冲突。然而,static 仅为 变量函数 提供此功能,而不适用于类型。这就是匿名命名空间的作用:它们提供了一种统一的方式来防止 任何 标识符发生名称冲突。 - sbi
1
还可以参考刚刚出现的关于内部链接的这个问题 - sbi

4
  1. 是的,只有一个变量x
  2. 是的,只有一个变量x
  3. 是的,只有一个变量x
  4. 在启动和关闭时。
  5. 我没有理解这个问题。
  6. 我相信1-4条是标准规定。

它与您将其定义为static完全相同:在文件内部全局,在外部隐藏。

static int x; 
namespace { 
  void Helper() { 
  } 
}

未命名命名空间是专门为消除static的特定用法而添加的(static有太多不同的含义/用法)


我说得对吧,这本质上和我声明一个相同的变量为静态是一样的? - drumsta

0
  1. 是的。命名空间为'x'指定了一个花哨的名称,但它仍然是一个全局范围内的静态对象。

  2. 可能。线程不是ISO C++虚拟机的一部分,这在标准文档中有所描述。C++如何与线程交互是一种实现定义的问题。大多数编译器都有一些declspec指令,使变量成为线程本地变量,否则所有线程共享同一个实例。

  3. 没有区别。

  4. x是一个int。它的值未定义/未初始化。如果它是一个类,则将在main()之前构造它,并在之后析构它。

5&6. 不理解问题。

我有一个c++问题的常用资源:c++ faq lite


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