我正在尝试确定以下代码是否安全,或者它是否为UB并且在这种情况下恰好运行良好(运行它here):
#include <iostream>
#include <mutex>
struct Foo
{
std::mutex mutex;
~Foo()
{
std::lock_guard<std::mutex> lock(mutex);
}
};
int main()
{
{
Foo foo;
}
std::cout << "everything seems to work fine...?" << std::endl;
}
具体来说,在成员变量出现之前,我们是否可以保证在析构函数中定义的局部变量被破坏?
我从cppreference.com找到了以下内容,但它似乎没有完全回答我的问题:
破坏序列
对于用户定义或隐式定义的析构函数,在执行析构函数体之后,编译器按照声明的相反顺序调用类的所有非静态非变体成员的析构函数,然后调用析构函数所有直接的非虚基类按照构造的相反顺序(反过来调用它们的成员及其基类的析构函数等),然后,如果这个对象是派生最多的类,它调用所有虚拟的析构函数基地。
根据[class.dtor] / 9中的标准,
在执行析构函数的主体并销毁在主体内分配的任何自动对象之后,类
X
的析构函数调用X
的直接非变量非静态数据成员的析构函数,X
的非虚拟直接基类的析构函数,如果X
是派生类最多的类(15.6.2),它的析构函数调用X
虚拟基类的析构函数。 ...
这肯定地回答了你的问题。
析构函数的主体在任何成员被破坏之前执行。从这个意义上说它是安全的。
但在问题是否安全之前,必须先询问是否有任何合理的用例来保存析构函数(以及构造函数)中的互斥锁。
只有一个线程可以构造或破坏对象。这必须通过对象外部的互斥锁来保证,例如,在工厂建设或在共享指针销毁。