在静态取消初始化期间静态分配的内存是否会无效?

时间:2010-09-24 09:35:39

标签: c++ memory static destructor

假设我已经定义了一个这样的变量(C ++):

static const char str[] = "Here is some string data";

我有一个静态分配的类实例,它在析构函数中引用了这个数组,这会出错吗?例如。 str 变量可能会以某种方式变得无效吗?

class A {
 ~A() {
   cout << str << endl;
 }
};

static A a;

我的假设是它不会出错,但我可以在任何地方找到它。我想肯定地知道这一点。我的假设是我们无法预测调用静态分配对象的析构函数的顺序,但是在进程被拆除之前,数据本身永远不会被释放。指向POD的含义指针应该是安全的,但不是对象实例。

含义,例如这样:

static const QString str = "Here is some string data";

static const std::string str = "Here is some string data";

无法安全地在 A 的析构函数中使用,因为它们都在堆上分配它们的字符串数据,并且在 A 的析构函数之前可能会被析构函数释放被称为。

我的假设是正确的吗?C ++标准中是否有任何部分解释这个或某些其他可以验证这一点的权威的链接?

3 个答案:

答案 0 :(得分:2)

调用自动,全局和静态对象的析构函数的顺序总是很明确:它与构造函数的调用顺序相反。因此,如果对象A引用对象B并且B A之前构建的,则可以确定B是< em>在 A之后被破坏。这给我们留下了构造函数顺序的问题。

这是我记得的:

  1. 在调用main()之前构造全局和静态对象。
  2. 类本地静态是在其类的任何对象之前构造的。
  3. 首次达到范围时,将构建函数局部静态。
  4. 同一翻译单元中的全局和静态对象按其定义的顺序构建。 (这意味着包含标题的顺序可能会影响这个!)
  5. 未定义跨翻译单元构建全局和静态对象的顺序
  6. 我对其中的一些有些模糊,所以如果你认为这是不对的,请纠正我。

答案 1 :(得分:2)

好的,我自己尝试阅读C ++标准,以找到答案。我从答案中看到,对于构造对象和分配对象之间的区别存在很多困惑。

来自标准:

  

3.6.2   初始化非本地对象

     

具有静态存储持续时间的对象   (3.7.1)应为零初始化   (8.5)在任何其他初始化之前   发生了。带静态的引用   存储持续时间和POD的对象   具有静态存储持续时间的类型   用常数初始化   表达式(5.19);这就是所谓的   不断初始化。一起,   零初始化和常量   初始化称为静态   初始化;所有其他   初始化是动态的   初始化。静态初始化   应在任何动态之前执行   初始化发生。动态   对象的初始化也是   有序或无序。

我对此的解释是,在运行任何构造函数之前,始终保证设置 const char []

  

3.6.3终止   用于静态存储持续时间的初始化对象的析构函数(12.4)(在块作用域或命名空间作用域中声明)是    作为从main返回并调用std :: exit(18.3)的结果调用。这些物体被摧毁了   完成构造函数或完成动态初始化的相反顺序。如果一个对象是   静态初始化,对象以与动态初始化对象相同的顺序销毁。

从我可以从这个带有常量表达式的 POD 类型中读取的内容将在任何对象类型之前被初始化并在任何对象类型之后被销毁。这意味着没有代码可以在无效时访问它们。

这应该解释为什么Google的C ++代码标准说你应该只使用POD types with constant expressions.

  

因此,我们只允许静态变量包含POD数据。此规则完全禁止向量(使用C数组)或字符串(使用const char [])。

答案 2 :(得分:0)

如果我没记错的话,全局对象初始化没有在标准中定义(或定义不明确),使得全局对象难以相互引用。

如果你想确定初始化顺序,请使用包含静态对象的全局函数,只返回它。您现在可以保证静态对象将在第一次函数调用时初始化。

破坏将在应用程序结束时发生,一旦退出main()。