#c #c 11
#c #c 11
Вопрос:
Допустим, у меня есть класс с массивом элементов std::atomic
s, где размер массива определяется с помощью вычисления (т. Е. Он может изменяться на основе других констант в другом месте программы):
class Foo {
static constexpr size_t kArraySize = ComputeArraySize();
std::atomic<size_t> atomics_[kArraySize];
};
Какой самый элегантный способ гарантировать, что все атомарные элементы инициализированы до
нуля? Могу ли я сделать лучше, чем перебирать массив в Foo
конструкторе и
явно сохранять ноль? Отличается ли ответ для std::array
?
Обычно я бы использовал здесь инициализатор фигурных скобок, но производная длина (которая может быть длинной) затрудняет это.
Обратите внимание, что я не могу предположить, что экземпляр Foo
имеет статическую продолжительность хранения.
Комментарии:
1. объявить как
std::atomic<size_t> atomics_[kArraySize] = {};
? Я не уверен, какие правила существуют для атомной инициализации2. … Ничего не делать. Все статическое инициализируется нулем при запуске программы.
3. @Ryan Haining: Да, это работает для простого массива в стиле C. Похоже, это не работает
std::array<std::atomic<size_t>, N>
, хотя стандарт, похоже, говорит, что это должно быть. @n.m.: «Обратите внимание, что я не могу предположить, что экземпляр Foo имеет статическую продолжительность хранения».4. «Похоже, не работает для std::array<std::atomic<size_t>, N>». Работает для меня. Какую версию компилятора вы используете?
5. Я могу поручиться за это. Он работает, как и ожидалось, с gcc 4.8.2 и clang 3.4.1.
Ответ №1:
Хорошо, я полагаю, что я проработал это. Оба из них будут инициализировать все атомы до нуля:
std::atomic<size_t> plain_array[kArraySize] = {};
std::array<std::atomic<size_t>, kArraySize> std_array = {};
Вот логика:
-
[dcl.init.aggr]/1 определяет массивы как агрегированные.
-
[array.cons]/1 требует, чтобы это
std::array
также было агрегированным. -
[dcl.init.aggr]/7 говорит, что если в списке инициализаторов меньше элементов, чем элементов в совокупности, то остальные элементы должны быть инициализированы из пустого списка инициализаторов. В данном случае это все члены.
-
[dcl.init.list]/3 определяет инициализацию списка из пустого списка для класса с конструктором по умолчанию (как с
std::atomic
), чтобы вызвать инициализацию значения. -
[dcl.init]/7 говорит, что классы без пользовательских конструкторов инициализируются нулем. Предполагая, что
std::array<T>
он содержит массивT
, и что нулевое представлениеstd::atomic<size_t>
— это то, что мы ожидаем, тогда все в порядке.
Теперь std::atomic
у него есть пользовательский конструктор, просто не пользовательский конструктор по умолчанию (последний явно задан по умолчанию). Таким образом, он технически не соответствует условиям последнего пункта. Но, похоже, это ошибка в стандарте, и она была исправлена в более поздних проектах.
Комментарии:
1. Я считаю, что базовые атомарные объекты остаются в неинициализированном состоянии из-за неожиданного поведения, описанного в open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0883r0.pdf . Инициализация по умолчанию не делает того, что вы ожидаете здесь.
2. @Joe, похоже, был исправлен wg21.link/p0883