Bisakah saya daftar-menginisialisasi std :: vektor dengan penerusan yang sempurna dari elemen?


14

Saya perhatikan bahwa daftar agregasi inisialisasi std :: vector melakukan inisialisasi salin ketika bergerak lebih berlaku. Pada saat yang sama, banyak emplace_backs melakukan apa yang saya inginkan.

Saya hanya bisa menghasilkan solusi yang tidak sempurna untuk menulis fungsi templat ini init_emplace_vector. Ini hanya optimal untuk konstruktor nilai tunggal yang tidak eksplisit .

template <typename T, typename... Args>
std::vector<T> init_emplace_vector(Args&&... args)
{
  std::vector<T> vec;
  vec.reserve(sizeof...(Args));  // by suggestion from user: eerorika
  (vec.emplace_back(std::forward<Args>(args)), ...);  // C++17
  return vec;
}

Pertanyaan

Apakah saya benar-benar perlu menggunakan emplace_back untuk menginisialisasi std :: vector seefisien mungkin?

// an integer passed to large is actually the size of the resource
std::vector<large> v_init {
  1000,  // instance of class "large" is copied
  1001,  // copied
  1002,  // copied
};

std::vector<large> v_emplaced;
v_emplaced.emplace_back(1000);  // moved
v_emplaced.emplace_back(1001);  // moved
v_emplaced.emplace_back(1002);  // moved

std::vector<large> v_init_emplace = init_emplace_vector<large>(
  1000,   // moved
  1001,   // moved
  1002    // moved
);

Keluaran

Kelas largemenghasilkan informasi tentang salinan / gerakan (implementasi di bawah) dan output dari program saya adalah:

- initializer
large copy
large copy
large copy
- emplace_back
large move
large move
large move
- init_emplace_vector
large move
large move
large move

Implementasi kelas besar

Implementasi saya largehanyalah tipe yang dapat disalin / bergerak yang menyimpan sumber daya besar yang memperingatkan tentang penyalinan / pemindahan.

struct large
{
  large(std::size_t size) : size(size), data(new int[size]) {}

  large(const large& rhs) : size(rhs.size), data(new int[rhs.size])
  {
    std::copy(rhs.data, rhs.data + rhs.size, data);
    std::puts("large copy");
  }

  large(large&& rhs) noexcept : size(rhs.size), data(rhs.data)
  {
    rhs.size = 0;
    rhs.data = nullptr;
    std::puts("large move");
  }

  large& operator=(large rhs) noexcept
  {
    std::swap(*this, rhs);
    return *this;
  }

  ~large() { delete[] data; }

  int* data;
  std::size_t size;
};

Edit

Dengan menggunakan cadangan, tidak ada salinan atau pemindahan. Hanya large::large(std::size_t)konstruktor yang dipanggil. Emplace sejati.


1
Ini bukan inisialisasi agregat, Anda memanggil konstruktor yang mengambil a std::initializer_list.
super

std :: vector's constructor adalah kekacauan IMHO yang membingungkan, dan jika saya jadi Anda, saya akan benar-benar menghindari masuk ke dalamnya jika saya tidak benar-benar harus. Plus, jika Anda tahu konten vektor Anda sebelumnya (yang sepertinya memang demikian) - pertimbangkan sebuah std::array.
einpoklum

1
Yang operator=menghancurkan sumbernya sangat tidak biasa dan dapat menyebabkan masalah yang tidak terduga.
alain

1
init_emplace_vectordapat ditingkatkan denganvec.reserve(sizeof...(Args))
Indiana Kernick

1
@ alain operator=tidak merusak sumbernya. Ini idiom copy-swap.
menghubungkan kembali

Jawaban:


11

Bisakah saya menggabungkan-menginisialisasi std :: vector ...

Tidak std::vectorbukanlah agregat, sehingga tidak dapat agregat-dijalankan.

Anda dapat berarti inisialisasi daftar sebagai gantinya, dalam hal ini:

Bisakah saya [daftar-inisialisasi] std :: vektor dengan penerusan sempurna elemen?

Tidak. Inisialisasi daftar menggunakan std::initializer_listkonstruktor dan std::initializer_listmenyalin argumennya.

init_emplace_vectorTampaknya Anda merupakan solusi yang layak, meskipun dapat ditingkatkan dengan menyimpan memori sebelum menggunakan elemen-elemen tersebut.


1
Terima kasih telah mengoreksi saya. Diedit. Poin bagus dengan cadangan.
menghubungkan kembali
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.