Подтвердить что ты не робот

Действительно ли 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 ведет себя иначе, чем встроенные типы в этом отношении?

4b9b3361

Ответ 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 является правильным в этом отношении.

Я не могу сказать вам, почему.