将std :: lock_guard保留在析构函数中是否安全?

时间:2019-05-01 21:31:28

标签: c++ multithreading destructor

我正在尝试确定以下代码是否安全,或者是否为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找到了以下内容,但似乎无法完全回答我的问题:

  

破坏顺序

     

对于用户定义或隐式定义的析构函数,在执行析构函数的主体之后,编译器将以声明的相反顺序为该类的所有非静态非变量成员调用析构函数,然后调用所有直接非虚拟基类的析构函数,其构造顺序相反(依次调用其成员及其基类的析构函数,等等),然后,如果此对象是派生程度最高的类,则将其称为析构函数所有虚拟基地。

2 个答案:

答案 0 :(得分:8)

根据[class.dtor] / 9中的标准,

  

执行析构函数的主体并销毁主体中分配的所有自动对象后,   类X的析构函数调用X的直接非变量非静态数据成员的析构函数,这些析构函数   X的非虚拟直接基类,如果X是派生程度最高的类的类型(15.6.2),则其析构函数   调用X的虚拟基类的析构函数。 ...

这肯定回答了您的问题。

答案 1 :(得分:1)

在销毁任何成员之前,将执行析构函数的主体。从这个意义上讲,它是安全的。

但是在问是否安全之前,必须先问是否有合理的用例将互斥量保存在析构函数(以及构造函数)中。

只有一个线程可以构造或破坏对象。必须通过对象的外部互斥量来确保这一点,例如在工厂建造时或在共享指针被破坏时。