29

It seems that std::atomic types are not copy constructible or copy assignable. Why?

Is there a technical reason why copying atomic types is not possible? Or is the interface limited on purpose to avoid some sort of bad code?

ildjarn
  • 62,044
  • 9
  • 127
  • 211
TianyuZhu
  • 752
  • 6
  • 8
  • 3
    I'm not happy with the answers given below (it's 2019 now). Hopefully someone has a better explanation? Maybe the original arguments as used by the C++ committee? – Carlo Wood Jan 31 '19 at 23:07

2 Answers2

32

On platforms without atomic instructions (or without atomic instructions for all integer sizes) the types might need to contain a mutex to provide atomicity. Mutexes are not generally copyable or movable.

In order to keep a consistent interface for all specializations of std::atomic<T> across all platforms, the types are never copyable.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
  • 2
    +1, I felt that was the reason, although I wasn't sure enough to post an answer. Maybe it is worth mentioning the `is_lock_free()` member function, which should tell if an implementation does actually rely on atomic instructions – Andy Prowl Mar 06 '13 at 14:38
  • I think you just mentioned it :) thanks. JoergB also gives a good (second) reason, which I couldn't put into words so didn't try to explain – Jonathan Wakely Mar 06 '13 at 16:12
  • 3
    I can't reconcile this answer with the fact that atomic_flag is guaranteed to be lock free, and is also uncopyable. – Nir Friedman Jul 05 '18 at 17:34
  • 3
    Obviously the copy constructor wouldn't copy the contained mutex, it would create a new (default constructed) mutex for the new atomic, in the same way that the existing atomic(T) constructor does. – ndkrempel May 29 '19 at 13:18
20
  1. Technical reason: Most atomic types are not guaranteed to be lock-free. The representation of the atomic type might need to contain an embedded mutex and mutexes are not copyable.

  2. Logical reason: What would it mean to copy an atomic type? Would the entire copy operation be expected to be atomic? Would the copy and the original represent the same atomic object?

There is no well-defined meaning for an operation spanning two separately atomic objects that would make this worthwhile. The one thing you can do is transfer the value loaded from one atomic object into another. But the load directly synchronizes only with other operations on the former object, while the store synchronizes with operations on the destination object. And each part can come with completely independent memory ordering constraints.

Spelling out such an operation as a load followed by a store makes that explicit, whereas an assignment would leave one wondering how it relates to the memory access properties of the participating objects. If you insist, you can achieve a similar effect by combining the existing conversions of std::atomic<..> (requires an explicit cast or other intermediate of the value type).

.

JoergB
  • 4,383
  • 21
  • 19
  • 9
    I don't understand your technical reason. Obviously the copy constructor wouldn't copy the contained mutex, it would create a new (default constructed) mutex for the new atomic, in the same way that the existing atomic(T) constructor does. – ndkrempel May 29 '19 at 13:11
  • 1
    The logical reason only applies to assignment. For construction, there's no issue because there can't be any other operations on the new `atomic` until after its construction is complete anyway. – David Schwartz Jul 29 '20 at 05:49