在C++11中将一个元素从std::deque中移动

9
我们知道std::deque::front()返回deque的第一个元素的引用。 我想知道这段代码是否总是安全的:
//deque of lambdas
deque<function<void(void)>> funs;

// then is some other place:
// take a lock
m.lock();
auto f = move(funs.front()); // move the first lambda in f
funs.pop_front(); // remove the element from deque //now the value is hold by f
m_.unlock(); // unlock the resorce
f(); //execute f

我已经使用gcc-4.9尝试了这段代码,它可以正常工作,但我不知道我们是否可以认为这段代码是安全的!


1
这几乎是有效的代码。几乎 - 因为您没有检查是否为空。存储元素的移动是安全操作。 - bobah
1
错别字报告:您在 m 上使用了 lock(),而在 m_ 上使用了 unlock() - Notinlist
最大的安全问题可能是“using namespace std” ;) 另请参阅https://dev59.com/D3M_5IYBdhLWcg3wQQ3w - Chris
1个回答

10

std::function的移动构造函数不能保证不抛出异常,所以你有一个异常安全性问题。由于你没有使用RAII锁来锁定m,如果auto f = move(funs.front());抛出异常,它将保持锁定状态。你可以使用std::unique_lock来解决这个问题:

std::unique_lock<decltype(m)> lock{m};
if (!funs.empty()) {
  auto f = move(funs.front()); // move the first lambda in f
  funs.pop_front(); // remove the element from deque //now the value is hold by f
  lock.unlock(); // unlock the resorce
  f(); //execute f
}

或者std::lock_guard

function<void()> f;
{
  std::lock_guard<decltype(m)> lock{m};
  if (!funs.empty()) {
    f = move(funs.front()); // move the first lambda in f
    funs.pop_front(); // remove the element from deque //now the value is hold by f
  }
}
if (f) f(); //execute f

嗨,Casey,目前来看,最好的解决方案可能是第一个,因为在第二种情况下,Lambda 将存储到堆中,出于性能原因,最好使用 auto。 - Gian Lorenzo Meocci
2
@GianLorenzoMeocci 为什么使用 auto 可以提高性能?在第一个代码片段中,auto f 将与 decltype(move(funs.front())) f 完全相同。因此,在第二个代码片段中声明 decltype(move(funs.front())) f 将会得到相同的结果。 - Walter
因为使用auto,你将会把lambda表达式存储在堆栈中。 - Gian Lorenzo Meocci

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接