使用引用参数在无锁pop()中返回值的缺点

Raz*_*ver 4 c++ multithreading reference smart-pointers lock-free

我目前正在阅读Williams"C++ Concurrency in Action".现在我停止了专门用于实现无锁pop()的主题.

无锁弹出:

void pop(T& result)
{
 node* old_head = head.load();
 while(!head.compare_exchange_weak(old_head,old_head->next));
 result=old_head->data;
}
Run Code Online (Sandbox Code Playgroud)

以下是对此代码的讨论的引用:

第二个问题是异常安全问题.当我们在第3章中首次介绍线程安全堆栈时,您看到如何按值返回对象会给您带来异常安全问题:如果在复制返回值时抛出异常,则该值将丢失.在这种情况下,传入对结果的引用是一个可接受的解决方案,因为如果抛出异常,您可以确保堆栈保持不变.不幸的是,在这里你没有那么奢侈; 一旦您知道自己是返回节点的唯一线程,您就只能安全地复制数据,这意味着该节点已从队列中删除.因此,通过引用传递返回值的目标不再是一个优点:您可能只是按值返回.如果要安全地返回值,则必须使用第3章中的其他选项:返回指向数据值的(智能)指针

我不明白引用的使用如何导致异常问题.我在这里看到'copy'这个词,但它不能用于引用,'初始化','赋值',但肯定不是'复制'.所以,我不明白在这个'副本'之后写的每一个.

谷歌搜索时,我找到了威廉姆斯的解释:https://forums.manning.com/posts/list/30887.page

但这并没有为我澄清这个问题,因为他再次使用带有参考文献的"复制":

"正常"堆栈:

void pop(T& value)
{
 std::lock_guard<std::mutex> lock(m);
 if(data.empty()) throw empty_stack();
 value=data.top();
 data.pop();
}
Run Code Online (Sandbox Code Playgroud)

使用"普通"堆栈,结果的参考参数的优点是您可以从堆栈中删除节点之前复制结果,并且如果复制到结果抛出,则节点仍然在那里进行另一次调用采取.

这是我的问题:在这种情况下使用引用是否会导致异常的产生,以及为什么我可能只是按值返回?

Ale*_*nov 5

当你result=old_head->data;复制old_head->datain-to时result.你是对的,在这种情况下使用赋值运算符而不是复制构造函数.但这并不重要,重要的是可能需要一些非常重要的操作来复制数据old_head->data,result并且操作可能会触发异常.

我认为威廉姆斯使用"复制"这个词,因为它是可以在这里使用的最普遍的世界.他还谈到返回一个值,在这种情况下,可能会调用复制构造函数,移动构造函数,赋值运算符和移动赋值运算符,具体取决于代码.他没有使用大量动词膨胀文本,而只使用"复制"一词,因为唯一重要的部分是我们在一个地方拥有数据而在另一个地方需要它.