【问题标题】:Which will be executed first, RAII or function return value哪个会先执行,RAII或函数返回值
【发布时间】:2013-11-24 07:11:51
【问题描述】:

MyClass 有一个需要返回其成员变量的成员函数,并且 该函数必须是线程安全的,所以我使用互斥锁来保护数据。

我有两个实现如下:

版本 1:

string MyClass::name() {
    m_mutex.lock();
    string temp = m_name;
    m_mutex.unlock();
    return temp;
}

版本 2:

string MyClass::name() {
    MutexLocker lock(mutex);
    return m_name;
}

我知道版本1没有问题,但我需要输入更多代码。

问题是,我不确定版本 2 是否正确。会不会在线程访问m_name之前释放互斥锁?

【问题讨论】:

  • 既然您知道版本 2 是正确且安全的,那么我可以争辩说版本 1 可能不安全,就像在可能出现异常的情况下不受 RAII 包装器保护的任何操作一样(以及疏忽释放资源)。 RAII 版本不仅减少了键入工作量,而且还使您的代码非常安全。这就是我所说的双赢!

标签: c++ multithreading


【解决方案1】:

版本 2 也是正确的(事实上,它比第一个版本更好!)。

在互斥量通过本地对象的析构函数释放之前首先复制该值。相反是不可能的,因为本地对象在超出范围时会被销毁,但是您必须注意 return 语句必须在范围内执行,因此必须在销毁之前发生。反之,本地对象超出范围后,return 语句将无法执行。

从调用堆栈的角度来看,本地对象在堆栈开始展开时被销毁,但包含 return 语句的函数在堆栈展开之前很久就执行了。这可以确保在释放互斥锁之前大量复制 m_name

或者想想这个简单的代码:

std::string f()
{
    std::string s = "Nawaz";
    return s; //Think of this line!
}

s 被销毁后1被复制了吗?这甚至可能吗?如果s 被复制它被破坏之后,它会不会让 C++ 编程变得不可能?

1.或者更好地说,感动。 :-)

【讨论】:

  • 很高兴知道 RAII 在这种看似边缘的情况下不会失败。
  • @MarkGarcia:这根本不是极端情况。如果它不同,它将无法返回任何复杂的局部变量。
  • 我实际上认为版本 2 不仅很好,而且实际上是更安全的方法。如果在锁定和解锁之间抛出异常,则互斥锁永远不会解锁。
  • Is s copied after its destruction? 在某些情况下,它根本不会被复制或销毁(好吧,实际上后来被销毁了,但在f() 中没有)。 ;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多