Как реализован std::atomic‹T›::operator= для неизменяемых типов?

Я узнал, что один из способов общения между потоками — совместное использование некоторой атомарной структуры данных. Например:

struct Point {
    int const x, y;
};

std::atomic<Point> some_point_in_shared_memory{Point{0, 0}};

Несмотря на то, что Point::operator=(Point const &) был удален, кажется, нет проблем с вызовом оператора присваивания для std::atomic<Point> следующим образом:

some_point_in_shared_memory = Point{1, 2};

Как можно реализовать эту операцию?

Одно из решений, о котором я мог бы подумать, - это использовать placement new для создания нового объекта поверх старого, но, по-видимому, это не безопасно для исключений. Или это нормально, потому что Point тривиально копируется?


person Benny K    schedule 31.08.2020    source источник
comment
Можете ли вы уточнить, что, кажется, нет проблемы? Ваш код компилируется? Если это так, в вашей стандартной библиотеке есть ошибка, поскольку std::atomic<T> требует, чтобы T можно было легко скопировать.   -  person alter igel    schedule 31.08.2020
comment
gcc и clang принимают это. MSVC и ICC этого не делают.   -  person François Andrieux    schedule 31.08.2020
comment
@alterigel см. это. Также отредактировал ссылку на нет проблем. Кроме того, Point легко копируется.   -  person Benny K    schedule 31.08.2020
comment
Где вы удаляете Point::operator=(Point const &)? Вы объявили Point простой структурой, так что это не похоже на минимально воспроизводимый пример. Кроме того, ваш заголовок по-прежнему говорит о неизменности. Это действительно то, что вы имели в виду?   -  person Peter Cordes    schedule 01.09.2020
comment
Кроме того, скомпилируйте с включенной оптимизацией, чтобы упростить вывод asm до ожидаемого хранилища qword seq-cst, реализованного с помощью xchg для его неявного поведения lock. godbolt.org/z/sdTEv9   -  person Peter Cordes    schedule 01.09.2020
comment
@PeterCordes Point — это неизменяемый тип, поскольку целые числа x и y являются постоянными, и по этой причине оператор присваивания неявно удаляется. Пример воспроизводим, как вы сами заметили. И приятно видеть, что это оптимизировано до одной команды xchg, но это не имеет ничего общего с исходным вопросом.   -  person Benny K    schedule 01.09.2020
comment
Ах да, я не заметил const в объявлении.   -  person Peter Cordes    schedule 01.09.2020
comment
Простой A заключается в том, что атомарные операции всегда реализуются с точки зрения доступа к битам, а не к объектам высокого уровня; вот почему никогда не ожидалось, что std::atomic<std::string> будет работать, когда он прошел компиляцию. Вы можете вызывать memcpy для struct Point с точки зрения типов и правильности константы (целевой объект типа struct Point не является константой), но поведение может быть определено или не определено в зависимости от интерпретации слов каждого стандарта.   -  person curiousguy    schedule 09.09.2020


Ответы (1)


Из cppreference:

Первичный шаблон std::atomic может быть создан с любым типом T TriviallyCopyable, удовлетворяющим требованиям CopyConstructible и CopyAssignable. Программа некорректна, если любое из следующих значений ложно:

std::is_trivially_copyable<T>::value
std::is_copy_constructible<T>::value
std::is_move_constructible<T>::value
std::is_copy_assignable<T>::value
std::is_move_assignable<T>::value

Ваш T не является CopyAssignable, и эта строка

some_point_in_shared_memory = Point{1, 2};

плохо сформирован. Должна быть ошибка компилятора. К сожалению, я не заставил GCC выдать ошибку или предупреждение (-pedantic -Wpedantic -pedantic-errors -Wall -Werror=pedantic безрезультатно).

person 463035818_is_not_a_number    schedule 31.08.2020
comment
Нам нужны понятия - person Slava; 31.08.2020
comment
@BennyK Я не понимаю, что ты говоришь. Если Point является неизменным, то, скорее всего, вам не нужно std::atomic<Point>, потому что уже Point можно только читать, а не записывать - person 463035818_is_not_a_number; 31.08.2020