为什么允许复制赋值给volatile std::atomic?

huangapple go评论69阅读模式
英文:

Why is copy assignment of volatile std::atomics allowed?

问题

std::atomic已删除复制赋值运算符。因此,以下代码会导致编译错误:

std::atomic<int> a1, a2;
a1 = a2; // 错误

我认为删除这些运算符的原因在这篇帖子等地有解释。到目前为止,一切都好。

但是我注意到,添加volatile使代码突然能够编译通过(在godbolt上在线演示):

volatile std::atomic<int> a1, a2;
a1 = a2; // 正常

对于我的项目,我实际上并不需要volatile变量,所以这只是出于好奇:这是否是C++标准的疏忽,还是故意的(为什么)?

注意:我可以通过修改std::atomic的定义来获得编译错误,方法之一是添加以下内容:

atomic & operator=(const volatile atomic &) volatile = delete;

或者删除转换运算符operator T() const volatile noexcept

英文:

std::atomic has deleted copy assignment operators. Hence, the following results in a compiler error:

std::atomic<int> a1, a2;
a1 = a2; // Error

I think the motivation for the deleted operators is explained e.g. in this post. So far, so good.
But I noticed, that adding volatile causes the code to compile suddenly (live on godbolt):

volatile std::atomic<int> a1, a2;
a1 = a2; // OK

I do not really require volatile variables for my project, so this is just out of curiosity: Is this an oversight in the C++ standard, or is this deliberate (why?)?

Note: I can get a compiler error by hacking the std::atomic definition, either by adding

atomic & operator=(const volatile atomic &) volatile = delete;

or by removing the conversion operator operator T() const volatile noexcept.

答案1

得分: 9

这是LWG3633


std::atomic<T>具有(已删除的)复制赋值运算符,接受const atomic<T>&(1),接受T的赋值运算符函数(2),以及到T的(非显式)转换函数(3):

// (1)
atomic& operator=(const atomic&) = delete;
atomic& operator=(const atomic&) volatile = delete;

// (2)
T operator=(T) noexcept;
T operator=(T) volatile noexcept;

// (3)
operator T() const noexcept;
operator T() const volatile noexcept;

当赋值源是非volatile的std::atomic<T>时,两个赋值运算符函数都是可行的,但首选(1),因为它不需要右操作数上的用户定义的转换。

当右操作数是volatile时,(1)不可行,因为const atomic<T>&无法绑定到volatile glvalue,因此选择(2)。

英文:

This is LWG3633.


std::atomic<T> has a (deleted) copy assignment operator taking a const atomic<T>& (1), an assignment operator function taking a T (2), and a (non-explicit) conversion function to T (3):

// (1)
atomic& operator=(const atomic&) = delete;
atomic& operator=(const atomic&) volatile = delete;

// (2)
T operator=(T) noexcept;
T operator=(T) volatile noexcept;

// (3)
operator T() const noexcept;
operator T() const volatile noexcept;

When the assignment source is a non-volatile std::atomic<T>, both assignment operator functions are viable, but (1) is preferred because it does not require a user-defined conversion on the right operand.

When the right operand is volatile, (1) is not viable because const atomic<T>& cannot bind to a volatile glvalue, so (2) is chosen.

huangapple
  • 本文由 发表于 2023年7月17日 20:54:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/76704682.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定