繁体   English   中英

静态取消初始化期间,静态分配的内存会变得无效吗?

[英]Can static allocated memory become invalid during static deinitialization?

说我已经定义了一个像这样的变量(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 ++标准中是否有任何部分对此进行了解释,或者是否与其他可以验证这一点的机构建立了链接?

始终自动定义自动,全局和静态对象的析构函数的调用顺序:这与构造函数的调用顺序相反。 因此,如果对象A引用了对象B并且B A 之前构造 ,则可以确保B A 之后破坏 这给我们留下了构造函数顺序的问题。

这是我记得的内容:

  1. 全局和静态对象是在调用main()之前构造的。
  2. 类本地静态变量在其类的任何对象之前构造。
  3. 首次达到它们的作用域时,将构造函数局部静态变量。
  4. 相同翻译单元中的全局和静态对象是按定义顺序构造的。 (这意味着标头的包含顺序可能会影响此!)
  5. 跨翻译单元的全局和静态对象的构造顺序是不确定的。

我对其中一些内容有些模糊,因此,如果您认为这不正确,请更正我。

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

从标准:

3.6.2初始化非本地对象

具有静态存储持续时间(3.7.1)的对象应在进行任何其他初始化之前进行零初始化(8.5)。 可以使用常量表达式(5.19)初始化具有静态存储持续时间的引用和具有静态存储持续时间的POD类型的对象。 这称为常量初始化。 零初始化和常量初始化合在一起称为静态初始化。 所有其他初始化是动态初始化。 静态初始化应在任何动态初始化发生之前执行。 对象的动态初始化是有序的或无序的。

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

3.6.3终止静态存储持续时间的初始化对象的析构函数(12.4)(在块作用域或命名空间作用域声明)是从main返回和调用std :: exit(18.3)的结果。 这些对象按照其构造函数完成或动态初始化完成的相反顺序销毁。 如果对象是静态初始化的,则该对象的破坏顺序与该对象被动态初始化的顺序相同。

据我所知,具有常量表达式的POD类型将在任何对象类型之前进行初始化,并在任何对象类型之后进行销毁。 这意味着在它们无效时,将不会运行任何可以访问它们的代码。

哪个应该解释为什么Google的C ++代码标准说您应该只使用带有常量表达式的POD类型。

结果,我们只允许静态变量包含POD数据。 此规则完全禁止使用vector(改为使用C数组)或string(使用const char [])。

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

如果您想确定初始化顺序,请在其中使用带有静态对象的全局函数,然后将其返回。 现在,您将保证在第一个函数调用时将初始化静态对象。

一旦脱离main(),销毁将在应用程序末尾发生。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM