Ініціалізація вектора атомів


12

Поміркуйте:

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

Чи вміст foo зараз дійсний? Або мені потрібно явно прокрутити і ініціалізувати їх? Я перевірив Godbolt, і це здається прекрасним, проте стандарт здається дуже заплутаним у цьому питанні.

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

Я думаю, що цей ефект ініціалізації значення застосовується:

2) якщо T - тип класу з конструктором за замовчуванням, який не надається користувачем, ані видаляється (тобто це може бути клас із неявно визначеним або дефолтним конструктором за замовчуванням), об'єкт ініціалізується нулем і тоді він ініціалізовано за замовчуванням, якщо він має нетривіальний конструктор за замовчуванням;

Тож мені здається, що атома нульова ініціалізація. Отже, питання полягає в тому, чи нульова ініціалізація astd::atomic<int> результату у дійсному об'єкті?

Я буду здогадуватися, що відповідь "так на практиці, але насправді це не визначено"?

Примітка. Ця відповідь погоджується з тим, що вона нульова ініціалізована, але насправді не говорить, якщо це означає, що об'єкт дійсний.

Відповіді:


7

Ви правильно турбуєтесь. Відповідно до стандарту, атома має конструктор за замовчуванням, який називається, однак вони не були ініціалізовані як такі. Це тому, що конструктор за замовчуванням не ініціалізує атомний:

Ініціалізований за замовчуванням std::atomic<T>не містить Tоб'єкт, і єдиним його дійсним використанням є знищення та ініціалізація std :: atomic_init

Це дещо порушує нормальні мовні правила, і деякі реалізації все одно ініціалізуються (як ви зазначали).

Зважаючи на це, я рекомендую зробити додатковий крок, щоб на 100% переконатися, що вони ініціалізовані правильно відповідно до стандарту - адже ви маєте справу з одночасністю, де помилок можна надзвичайно важко відстежити.

Існує багато способів уникнути проблеми, включаючи використання обгортки:

struct int_atomic {
   std::atomic<int> atomic_{0};//use 'initializing' constructor
};

Або реально використовувати atomic_init. Вам вже доведеться синхронізувати навколо коду у питанні
гонки

Конструктор за замовчуванням є тривіальним , так що НЕ називається в будь-якому випадку (в цитаті в питанні)
светлота Гонка в Orbit

@LightnessRaceswithMonica, що теж можливо, я просто хотів виділити обгортку
darune

@LightnessRaceswithMonica - це виняток із звичайних мовних правил - навіть якщо деякі компілятори не застосовують цього винятку. Я не впевнений, що відповідь StoreTeller є 100% точним.
darune

2

Навіть якщо конструктор за замовчуванням був названий (це не так, тому що це тривіально), він насправді нічого не робить .

Нульова ініціалізація очевидно не може бути гарантована для отримання дійсної атомної; це спрацює лише в тому випадку, якщо випадково буде створено дійсний атом шляхом нульової ініціалізації всіх його членів.

Оскільки атома не підлягає копіюванню, ви не можете надати значення ініціалізації у векторному конструкторі.

Тепер слід перевести петлю над контейнером та std::atomic_initкожним елементом. Якщо вам потрібно зафіксувати це, це добре, тому що ви вже синхронізуєте створення вектора з тієї ж причини.


@darune Я вважаю, що це свого роду синхронізація;)
Гонки
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.