首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >并发安全堆栈接口方法:是否正确?

并发安全堆栈接口方法:是否正确?
EN

Stack Overflow用户
提问于 2019-12-16 10:37:52
回答 1查看 37关注 0票数 1

我偶然发现了一个用于stack<>::pop()的接口方法的线程安全堆栈实现:

代码语言:javascript
复制
void pop(T& value)
 {
 std::lock_guard<std::mutex> lock(m);
 if(data.empty()) throw empty_stack();
 value=std::move(data.top()); <----- why not just value = data.top()?
 data.pop();
 }

当然,我的问题与并发无关,但是为什么将堆栈顶部的值移到变量值中呢?我的理解是,一旦它被移动,你就不能弹出它,因为它已经不在了。

这要么是我发现它的源头上的错误,要么是如果有人能向我解释的话,我会心存感激。

谢谢你,阿敏

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-12-16 10:57:11

value=std::move(data.top());<-为什么不只是data.top= data.top()?

这在很大程度上取决于T是什么,基本上,如果移动构造函数存在,它将尝试使用移动构造函数,T(T &&mv)而不是复制构造函数T(const T &cp)

在这两种情况下,将为data.pop();行上的原始对象调用data.pop();

首先,使用移动构造函数可能是必需的。有些对象是可移动的,但不能复制,例如unique_ptr

第二,在提供搬迁的情况下,往往效率更高。例如,假设T是一个std::vector,复制构造函数将分配另一个数组,然后对每个元素进行复制(这可能也很昂贵),然后它将删除原始数组。这太浪费了。

move构造函数只是通过将内部数据数组从一个向量移动到一个新的向量来保留原始元素,并将原始元素(在本例中将被删除)保持在一个未指定但有效的状态(可能是“空”)。

它可能看起来像:

代码语言:javascript
复制
template<typename T> class vector
{
public:
    vector<T>(vector<T> &&mv)
        : arr(mv.arr) , arr_len(mv.arr_len), arr_capacity(mv.arr_capacity)
    {
        mv.arr = nullptr;
        mv.arr_len = 0;
        mv.arr_capacity = 0;
    }
    ...
private:
    T *arr;
    size_t arr_len;
    size_t arr_capacity;
};

由于在一般情况下,原始对象状态是“未指定的”,如果要继续使用原始对象,则必须小心。像在pop案例中那样销毁它是可以的,就像任务一样。

代码语言:javascript
复制
T tmp = std::move(some_value);
some_value.foo(); // In general, what state some_value is in is unknown, this might vary even from compiler to compiler
some_value = some_other_value; // But assignment should work
some_value.foo(); // So it is now in a known state

例如,可以在不复制任何“内容”的情况下实现“交换”。

代码语言:javascript
复制
template<typename T>  void swap(T &a, T &b)
{
    T tmp = std::move(a);
    a = std::move(b);
    b = std::move(tmp);
}

许多类型将被更多地指定,例如对于std::vector,它承诺是empty()

代码语言:javascript
复制
std::vector<T> tmp = std::move(some_array);
assert(some_array.empty()); // guaranteed
some_array.push_back(x); // guaranteed to have one element

你不能弹出它,因为它已经不在那里了。

因此,重要的一点是,data.top()不移除元素,因此它仍然存在。而移动并没有真正删除这个东西,只是让它处于某种未指定的状态。

并发安全堆栈接口方法

在并发这个单独的主题上,这里的内容是访问值的top,以及删除它的pop处于相同的锁下。为了安全起见,对此实例堆栈的所有访问都必须使用相同的锁实例,因此确保任何data.push也持有该锁。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59354884

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档