Инициализация вектора атомности - PullRequest
11 голосов
/ 04 ноября 2019

Рассмотрим:

void foo() {
  std::vector<std::atomic<int>> foo(10);
  ...
}

Является ли содержимое foo действительным? Или мне нужно явно выполнить цикл и инициализировать их? Я проверил на Godbolt, и это выглядит нормально, однако стандарт в этом вопросе кажется очень запутанным.

Конструктор std :: vector говорит, что он вставляет default-вставленный экземпляров std::atomic<int>, которые значения инициализируются путем размещения new.

Я думаю, что этот эффект инициализации значения применяется:

2)если T является типом класса с конструктором по умолчанию, который не предоставлен и не удален пользователем (то есть это может быть класс с неявно определенным или дефолтным конструктором по умолчанию), объект инициализируется нулями, а затем он устанавливается по умолчанию. инициализируется, если имеет нетривиальный конструктор по умолчанию;

Так что мне кажется, что атомы инициализируются нулями. Итак, вопрос в том, приводит ли нулевая инициализация std::atomic<int> к действительному объекту?

Я собираюсь догадаться, что ответ «да на практике, но он не определен»?

Примечание: Этот ответ согласен с тем, что он инициализирован нулем, но на самом деле не говорит, означает ли это, что объект действителен.

Ответы [ 2 ]

7 голосов
/ 04 ноября 2019

Вы правы, что беспокоитесь. В соответствии со стандартом атомика имеет конструктор по умолчанию, но они не были инициализированы как таковые. Это связано с тем, что конструктор по умолчанию не инициализирует атомарный:

Инициализированный по умолчанию std::atomic<T> не содержит объект T, и его единственное допустимое использование - уничтожение и инициализация std :: atomic_init

Это несколько нарушает правила обычного языка, и некоторые реализации все равно инициализируются (как вы уже заметили).

Как говорится,Я бы порекомендовал сделать дополнительный шаг, чтобы убедиться на 100%, что они правильно инициализируются в соответствии со стандартом - после всего, что вы имеете дело с параллелизмом, где ошибки могут быть чрезвычайно трудно отследить.

Есть много способов избежатьпроблема, в том числе с использованием оболочки:

struct int_atomic {
   std::atomic<int> atomic_{0};//use 'initializing' constructor
};
2 голосов
/ 04 ноября 2019

Даже если был вызван конструктор по умолчанию (это не так, потому что он тривиален) он на самом деле ничего не делает .

Очевидно, что нулевая инициализация не может гарантировать получениедействительный атомный;это будет работать только в том случае, если случайно будет создан действительный атом при нулевой инициализации всех его членов.

И, поскольку атомы не копируются, вы не можете предоставить значение инициализациив конструкторе вектора.

Теперь вы должны перебрать контейнер и std::atomic_init каждого элемента. Если вам нужно обойти это, это нормально, потому что вы уже синхронизируете создание вектора по той же причине.

...