Inisialisasi vektor atom

12

Mempertimbangkan:

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

Apakah konten foo sekarang valid? Atau apakah saya perlu secara eksplisit mengulang dan menginisialisasi mereka? Saya telah memeriksa Godbolt dan tampaknya baik-baik saja, namun standar tampaknya sangat membingungkan pada titik ini.

The std :: vector konstruktor mengatakan itu menyisipkan default-dimasukkan contoh std::atomic<int>, yang nilai dijalankan melalui penempatan new.

Saya pikir efek inisialisasi nilai ini berlaku:

2) jika T adalah tipe kelas dengan konstruktor default yang tidak disediakan pengguna atau dihapus (yaitu, mungkin kelas dengan konstruktor default yang didefinisikan secara implisit atau default), objek tersebut diinisialisasi nol dan kemudian diinisialisasi diinisialisasi default jika memiliki konstruktor default non-sepele;

Jadi bagi saya tampaknya atom diinisialisasi nol. Jadi pertanyaannya adalah, apakah inisialisasi nol std::atomic<int>hasil dalam objek yang valid?

Saya akan menebak bahwa jawabannya adalah "ya dalam praktek tetapi tidak benar-benar didefinisikan"?

Catatan: Jawaban ini setuju bahwa ini nol-diinisialisasi, tetapi tidak benar-benar mengatakan jika itu berarti bahwa objek tersebut valid.

Timmmm
sumber

Jawaban:

7

Anda benar khawatir. Menurut standar, atom memiliki konstruktor default yang dipanggil, namun mereka belum diinisialisasi. Ini karena konstruktor default tidak menginisialisasi atom:

Default-diinisialisasi std::atomic<T>tidak mengandung Tobjek, dan satu-satunya kegunaan yang valid adalah penghancuran dan inisialisasi oleh std :: atomic_init

Ini agak melanggar aturan bahasa normal, dan beberapa implementasi menginisialisasi (seperti yang telah Anda catat).

Yang sedang berkata, saya akan merekomendasikan mengambil langkah ekstra untuk memastikan 100% mereka diinisialisasi dengan benar sesuai standar - setelah semua Anda berurusan dengan konkurensi di mana bug bisa sangat sulit dilacak.

Ada banyak cara untuk menghindari masalah ini, termasuk menggunakan pembungkus:

struct int_atomic {
   std::atomic<int> atomic_{0};//use 'initializing' constructor
};
sayang
sumber
Atau benar-benar digunakan atomic_init. Anda tetap harus menyinkronkan sekitar kode dalam pertanyaan
Lightness Races di Orbit
Konstruktor default bersifat sepele sehingga tidak disebut demikian (sesuai dengan kutipan dalam pertanyaan)
Lightness Races in Orbit
@LightnessRaceswithMonica juga memungkinkan, saya hanya ingin menyorot pembungkusnya
darune
@LightnessRaceswithMonica ini pengecualian untuk aturan bahasa normal - meskipun beberapa kompiler tidak menerapkan pengecualian ini. Saya tidak yakin jawaban StoreTeller adalah 100% akurat.
darune
2

Bahkan jika konstruktor default dipanggil (tidak, karena sepele) ia tidak benar-benar melakukan apa pun .

Inisialisasi nol jelas tidak dapat dijamin untuk menghasilkan atom yang valid; ini hanya akan berfungsi jika kebetulan atom yang valid dibuat dengan nol-menginisialisasi semua anggotanya.

Dan, karena atom tidak dapat disalin, Anda tidak dapat memberikan nilai inisialisasi dalam konstruktor vektor.

Anda sekarang harus mengulang wadah dan std::atomic_initsetiap elemen. Jika Anda perlu mengunci ini, itu bagus karena Anda sudah menyinkronkan kreasi vektor untuk alasan yang sama.

Lightness Races di Orbit
sumber
@ Darune Saya menganggap itu semacam sinkronisasi;)
Lightness Races di Orbit