Referencing a possibly destroyed static object

无人久伴 提交于 2019-12-23 08:36:03

问题


Assuming I have the following code

Something.hpp

#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;
}

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.


Edit

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

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 which contradicts the standard


回答1:


The order of construction and destruction of static (and global non-static) objects is well-defined in the C++ specification, for a single translation unit!

If you have multiple translation unit (multiple source files) then the order of construction/destruction between the TUs is not defined.

So the code you show can have undefined behavior.




回答2:


[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.

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

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

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

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

  2. 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.

  3. 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.

  4. 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.)



来源:https://stackoverflow.com/questions/41486703/referencing-a-possibly-destroyed-static-object

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!