I have two std::atomic variables, like this:
std::atomic<bool> b1;
std::atomic<bool> b2;
At some point in the code I need to swap them. This runs before the threads are created, so I know there is only the main thread and no-one else is trying to read/write to those vars. But:
std::swap(b1, b2);
This results in:
[...] MSVC\14.24.28314\include\utility(61,1): error C2280: 'std::atomic<bool>::atomic(const std::atomic<bool> &)': attempting to reference a deleted function
[...] MSVC\14.24.28314\include\atomic(1480): message : see declaration of 'std::atomic<bool>::atomic'
[...] MSVC\14.24.28314\include\atomic(1480,5): message : 'std::atomic<bool>::atomic(const std::atomic<bool> &)': function was explicitly deleted
I'm not sure why the copy constructor is deleted. So the solution I used was to use the old-style swap with a 3rd variable:
const bool tmp = b1;
b1 = b2.load();
b2 = tmp;
But now I'm curious: Why is std::atomic's copy constructor deleted?
(Actual code is more complicated than two single std::atomic<bool> variables, but I tried to distill it down to a simple case for this question.)
What you did isn't atomic. It has all sorts of possible data races from the moment b1 is loaded, until the moment b2 is set.
Presumably the reason swap is forbidden is that it's not possible to perform an atomic operation that modifies two unrelated memory addresses (at least, not portably enough to support it as a language standard), so it refuses to lie to you by silently using non-atomic swapping.
Conveniently, there are other reasons to prohibit copy construction, so the default implementation of std::swap is blocked as a side-effect of prohibiting copy construction, so all they had to do was refuse to provide a lying swap implementation themselves.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With