使用全局实例破坏类中的静态成员

时间:2018-03-05 14:43:54

标签: c++ static destructor member

我有一个带有静态非原始成员的类。例如:

sudo apt-get install ca-certificates

g_my_global_class被声明为全局变量,所以在离开main()之后调用它的析构函数。 但是,MyClass :: m_object是静态的,因此它也会在main()之后被销毁。

有没有保证~MyClass()会在MyClass :: m_object之前的〜SomeObject()之前执行?换句话说,当调用全局类实例的析构函数时,我可以假设此类的静态成员仍然可以访问,或者这取决于构造/销毁订单吗?

如果代码是按此顺序编写的,我认为g_my_global_class是后来构造的,因此应首先对其进行破坏。如果行

,事情就会改变
class SomeObject
{
    ... // something that will be destroyed in destructor,
        // like an array pointer.

public:
    SomeObject();
    ~SomeObject(); 
};

class MyClass
{
    static SomeObject m_object;

public:
    MyClass();
    ~MyClass(); // this will access m_object

    static bool SetupStaticMember();
};

/// Implementation of SomeObject and MyClass ///

SomeObject MyClass::m_object;
bool dummy = MyClass::SetupStaticMember(); // Setup the values in m_object, for example,
                                           // allocate memory that will be released in ~SomeObject().

MyClass g_my_global_class;

移动到另一个.cpp文件,其文件名导致订单更改?

4 个答案:

答案 0 :(得分:5)

首先,

bool dummy = MyClass::InitStaticMember(); // m_object is initialized here

实际上并不初始化静态成员。这发生在

之前的那一行
SomeObject MyClass::m_object;

所以,因为你基本上有

SomeObject MyClass::m_object;
MyClass g_my_global_class;

由于对象以相反的顺序被销毁,因此g_my_global_class之前MyClass::m_object被销毁。

现在,如果您将MyClass g_my_global_class;移至其他翻译单元,则所有投注均已关闭。订购仅在单个翻译单元中得到保证。

答案 1 :(得分:2)

  

是否可以保证在~MyClass() ~SomeObject()之前MyClass::m_object执行MyClass::m_object

是。静态存储中的对象与初始化的逆序相反。

按照定义的顺序初始化静态初始化的对象,例如g_my_global_classMyClass::m_object。因此,首先定义的class MyClass { static SomeObject& m_object() { static SomeObject s; return s; } }; 也首先被初始化,并且最后被销毁。

  

如果行...移动到另一个.cpp文件并且其文件名导致订单改变,那么会发生变化吗?

是的,事情发生了变化。翻译单位的定义顺序未指定,因此无法保证相对初始化顺序(因此无法保证相对销毁顺序)。

静态对象之间依赖关系的典型解决方案是在首次使用习惯用法时使用初始化,这只是将全局静态的使用替换为返回对本地静态的引用的函数:

MyClass::m_object()

当执行首次到达声明点时,初始化本地静态对象;因此成语的名称。

任何自己的初始化调用s的对象都保证在本地静态<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile> <RootNamespace>Broadcast</RootNamespace> <AssemblyName>Broadcast</AssemblyName> 被销毁之前被销毁,因此可以依赖它在整个生命周期中的存在 - 包括析构函数而不管翻译单位界限。

答案 2 :(得分:1)

如果您正在使用visual studio - windows,请查看此内容:否则您可能必须使用__PRETTY_FUNCITON__等类似内容。

class SomeObject {
public:
    SomeObject() {
        std::cout << __FUNCTION__ << " was called: SomeObject created." << std::endl;
    }
    ~SomeObject() {
        std::cout << __FUNCTION__ << " was called: SomeObject destroyed." << std::endl;
    }
};

class MyClass {
public:
    static SomeObject m_object;

    MyClass() {
        std::cout << __FUNCTION__ << " was called: MyClass created." << std::endl;
    }
    ~MyClass() {
        std::cout << __FUNCTION__ << " was called: MyClass destroyed." << std::endl;
    }

    static bool setupStaticMember() {
        std::cout << __FUNCTION__ << " was called... " << std::endl;
        return true;
    }

};

SomeObject MyClass::m_object;
bool dummy = MyClass::setupStaticMember();
MyClass gMyClass;

int main() {



    _getch();
    return 0;
}

在等待按键时在调试器控制台中输出:

SomeObject::SomeObject was called: SomeObject created.
MyClass::setupStaticMember was called...
MyClass::MyClass was called: MyClass created.

然后输入按键并关闭调试器的控制台(Visual Studio 2017)......

MyClass::~MyClass was called: MyClass destroyed.
SomeObject::~SomeObject was called: SomeObject destroyed.

要完全测试,只需直接转到控制台中的*.exe路径并调用可执行文件。在应用程序运行时,您将在上面看到相同的行,但在按下某个键并输入完成应用程序之后,将按顺序调用最后两行。

这些都在main.cpp文件中(相同的翻译单元)。

这确实显示了创建对象的顺序。现在,如果您处于类层次结构中,那么您需要确保正在虚拟化类以进行正确构建 - 销毁顺序。

答案 3 :(得分:0)

类的静态成员是类级变量,属于类范围。由于静态成员只在类的范围内,因此可以从具有::(classname :: static_variable)运算符的该类实例化的所有对象访问它。因为它不是对象变量,所以无法从类的析构函数中释放。

假设您已在代码中的不同位置创建了该类的十个对象,并且一个对象超出其范围并将调用其析构函数,如果从该析构函数中释放静态变量,其他对象中会发生什么?因为他们都共享相同的静态成员。这就是静态成员永远不会在构造函数中初始化的原因。

因此,只有在程序退出时才会从内存中释放静态成员。