j__
j__

Reputation: 740

std::atomic address after store

I can't seem to get the address of an atomic object after a store.

e.g.

std::atomic<int> i;
std::atomic<int>* p = &++i; // doesn't work
auto* p = &++i; // doesn't work
// below works:
++i;
auto* p = &i;

What's happening here and why?

To clarify: I know it returns an r-value. Why doesn't it return the original object, this? Is this a purposeful design choice or was it an oversight?

More specifically, what's happening under-the-hood for this requirement?

Upvotes: 1

Views: 559

Answers (1)

jtbandes
jtbandes

Reputation: 118681

While the pre-increment operator usually returns its operand by reference, in the case of std::atomic integers, it returns the new value as a temporary. So in your example ++i does not return a reference to the atomic<int> i itself, it returns the new value of i (i.e. an int). You can see this at: https://en.cppreference.com/w/cpp/atomic/atomic/operator_arith

It would be misleading and even dangerous to return a reference to the original atomic<int>, because to access the int value through this reference would require a second, separate read operation — so its value might be different from the value at the time of increment. (This isn't particularly relevant your example code, since you are only trying to obtain a pointer to the referenced object, but some code will actually access the value after ++ so this is why returning a reference isn't possible.)

In other words, if ++i returned a reference to the atomic<int> i, then

int j = ++i;

would be equivalent to

++i;
// ...other threads may modify the value of `i` here!...
int j = i;

The whole point of atomics is to perform reads and writes together as an indivisible operation, so ++i must internally use hardware/OS atomic operations to simultaneously read and increment the integer, so the new value is returned as a temporary.

If you're curious to see what's under the hood, here is libc++'s implementation where you can see that operator++ simply calls into fetch_add(1) and returns the result + 1.

Upvotes: 6

Related Questions