Действительно ли std:: atomic:: operator ++ действительно возвращает значение?
В соответствии с этим префикс std::atomic<T>::operator++
возвращает T
, поэтому этот код только увеличивает v
один раз:
template<class T> void addTwo(std::atomic<T>& v) {
++(++v);
}
Кроме того, std::atomic<T>::operator=
явно возвращает T
, поэтому этот код разыгрывает неверный указатель, который указывал на временный T
:
template<class T>
void setOneThenTwo(std::atomic<T>& v) {
auto ptr = &(v = 1);
*ptr = 2;
}
Я, безусловно, не предлагаю, чтобы эти образцы кода были хорошей практикой, однако мне очень удивительно, что std::atomic
ломает их. Я всегда ожидаю, что operator=
и префикс operator++
вернут ссылку на *this
.
Вопрос: Является ли cppreference прав о типах возврата здесь, и если да, есть ли веская причина, что std::atomic
ведет себя иначе, чем встроенные типы в этом отношении?
Ответы
Ответ 1
если operator++
вернул ссылку, это было бы ссылкой на std::atomic<T>
not to T
, и в этом случае вам нужно будет сделать дополнительный load
, чтобы получить текущее значение.
Представьте, что у вас есть СУБД, и вам нужно поддерживать поле "автоинкремент"
С помощью operator++
перенастройки T
вы можете сделать это
class AutoIncrement
{
public:
AutoIncrement() : current (0) {}
unsigned int next()
{
return ++current;
}
private:
std::atomic<unsigned int> current;
};
Теперь представьте operator++
возвращает std::atomic<T>&
В этом случае, когда вы делаете return ++current
, он будет делать две вещи
- Atomic read-modify-write
- Атомная нагрузка
Это две полностью независимые операции. Если другой поток вызывает next
между вами, вы получите неправильное значение для поля автоинкремента!
Ответ 2
В соответствии с [C++11: 29.6.5/32]
и [C++11: 29.6.5/10]
, да, cppreference.com является правильным в этом отношении.
Я не могу сказать вам, почему.