引用可能损坏的静态对象 [英] Referencing a possibly destroyed static object

查看:39
本文介绍了引用可能损坏的静态对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有以下代码

#pragma once

class Something {
public:
    static Something& get();
private: 
    Something();
};

Something.cpp

#include "Something.hpp"
#include <iostream>
using namespace std;

Something& Something::get() {
    static Something something;
    return something;
}
Something::Something() {
    cout << "Something()" << endl;
}

main.cpp

#include <iostream>
using namespace std;

struct SomethingElse {
    ~SomethingElse() {
        Something::get();
        cout << "~SomethingElse" << endl; 
    }
};

void func() {
    static SomethingElse something_else;
    // do something with something_else
}

int main() {
    func();
    return 0;
}

是否可以创建 Something 对象的多个实例?该标准对串行化销毁静态对象有何规定?

Can more than one instance of the Something object ever be created? Does the standard say anything about serializing the destruction of static objects?

注意,我知道在不同的翻译单元中,文件级静态变量的破坏是不确定的,我想知道在函数范围内的静态变量(

Note I am aware the the destruction of file level static variables is undefined when across different translation units, I wanted to know what happens in the case of function scoped static variables (which have the double-checked locking pattern built into the C++ runtime) For the same translation unit case with file level static variables, its easy for the compiler to ensure serialization with construction and destruction based on how the variables are laid out in the code (static), but what happens when the variables are dynamically lazily created when the functions are called?

注意:原始变量呢?我们可以期望它们在程序结束之前包含它们的值吗?因为它们不需要被销毁.

Note What about for primitive variables? Can we expect them to contain their values till program end? Since they don't need to be destroyed.

在cppreference.com上找到了此内容( http://en.cppreference.com/w/cpp/utility/program/exit )

Found this on cppreference.com (http://en.cppreference.com/w/cpp/utility/program/exit)

如果在线程局部或静态对象B之前对线程局部或静态对象A的构造函数的完成或动态初始化的顺序进行了排序,则在破坏A的开始之前按顺序对B的破坏的完成进行了排序.

If the completion of the constructor or dynamic initialization for thread-local or static object A was sequenced-before thread-local or static object B, the completion of the destruction of B is sequenced-before the start of the destruction of A

如果这是真的,那么每个静态对象的销毁序列化吗?但我也发现了

If this is true then destruction for every static object is serialized? But I also found this

https://isocpp.org/wiki/faq/ctors#construct-on-first-use-v2 与标准相抵触

推荐答案

[stmt.dcl]¶4

第一次在控件通过其声明时执行具有静态存储持续时间或线程存储持续时间的块范围变量的动态初始化.

Dynamic initialization of a block-scope variable with static storage duration or thread storage duration is performed the first time control passes through its declaration.

[basic.start.term]¶1

如果对具有静态存储持续时间的对象的构造函数的完成或动态初始化的排序要先于另一个对象的顺序进行,则在第二个对象的析构函数的初始化之前对第二个对象的析构函数的完成进行排序.

If the completion of the constructor or dynamic initialization of an object with static storage duration is sequenced before that of another, the completion of the destructor of the second is sequenced before the initiation of the destructor of the first.

¶2

如果函数包含具有静态或线程存储持续时间的块范围对象,并且该对象在具有静态或线程存储持续时间的对象的销毁过程中被调用,则该程序具有未定义的行为如果控制流通过了先前破坏的块范围对象的定义.

If a function contains a block-scope object of static or thread storage duration that has been destroyed and the function is called during the destruction of an object with static or thread storage duration, the program has undefined behaviour if the flow of control passes through the definition of the previously destroyed block-scope object.

正是在 SomethingElse 的析构函数中,我们冒着调用这种未定义行为的风险:

It is in the destructor of SomethingElse that we risk invoking this undefined behaviour:

SomethingElse::~SomethingElse() {
    Something::get();
}

如果存在具有静态存储持续时间的 SomethingElse 实例,则有四种可能性:

If there is an instance of SomethingElse with static storage duration, then there are four possibilities:

  1. Something 的单个实例是在 SomethingElse 之前构造的.它的破坏将在 SomethingElse 之后发生,因此行为已得到明确定义.

  1. The single instance of Something was constructed before the SomethingElse. Its destruction will happen after the SomethingElse, so the behaviour is well defined.

Something 的单个实例是在 SomethingElse 之后构造的.它的破坏将发生在 SomethingElse 之前,因此行为如上所述是不确定的.

The single instance of Something was constructed after the SomethingElse. Its destruction will have happened before the SomethingElse, so the behaviour is undefined as described above.

Something 的单个实例是在不同的线程中构造的,而与 SomethingElse 的构造没有同步.破坏可能同时发生,因此行为是不确定的.

The single instance of Something was constructed in a different thread without being synchronized with respect to the construction of the SomethingElse. The destructions may happen concurrently, so the behaviour is undefined.

尚未构建 Something 的实例(即,这是对 Something :: get 的首次调用).在这种情况下,程序要求在 SomethingElse 之后构造 Something ,这意味着 Something 的销毁必须在 SomethingElse ,但是由于已经开始销毁 SomethingElse ,因此这是一个矛盾,其行为是不确定的.(从技术上讲,先后顺序"关系中存在一个循环.)

No instance of Something was yet constructed (i.e. this is the first call to Something::get). In this case, the program calls for the construction of a Something after the SomethingElse, which means the destruction of the Something must happen before the SomethingElse, but since the destruction of the SomethingElse has already commenced, this is a contradiction, and the behaviour is undefined. (Technically, there is a cycle in the "sequenced before" relation.)

这篇关于引用可能损坏的静态对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆