Öğeleri mükemmel bir şekilde ileterek std :: vector'u listeleyebilir miyim?


14

Ben std :: vector toplam liste initalizasyon hareket daha uygulanabilir olduğunda kopya başlatma gerçekleştirdiğini fark ettim . Aynı zamanda, birden çok emplace_backs istediğimi yapar.

Ben sadece bir şablon fonksiyonu yazma bu kusursuz çözümü ile gelebilir init_emplace_vector. Bununla birlikte, sadece müstehcen olmayan tek değerli kurucular için idealdir .

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;
}

Soru

Gerçekten std :: vector'u olabildiğince verimli başlatmak için emplace_back kullanmam gerekir mi?

// 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
);

Çıktı

Sınıf largekopyalar / hamleler hakkında bilgi üretir (aşağıdaki uygulama) ve böylece programımın çıktısı:

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

Büyük sınıf uygulaması

Uygulamam large, kopyalama / taşıma konusunda uyaran büyük bir kaynağı tutan, kopyalanabilir / taşınabilir bir tür.

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;
};

Düzenle

Yedek kullanarak, kopya veya taşıma yoktur. Yalnızca large::large(std::size_t)yapıcı çağrılır. Gerçek imparatorluk.


1
Bu toplu başlatma değil, bir alan yapıcısını çağırıyorsunuz std::initializer_list.
Süper

std :: vector'un kurucuları kafa karıştırıcı bir karışıklık IMHO'ydu ve eğer ben olsaydım, kesinlikle zorunda değilsem içine girmekten gerçekten kaçınırdım. Ayrıca, vektörlerin içeriğini önceden bildiğinizi biliyorsanız (durum böyle olabilir) - bir düşünün std::array.
einpoklum

1
Bir operator=kaynağı yok eder oldukça sıradışı ve beklenmedik sorunlara neden olabilir.
alain

1
init_emplace_vectorile geliştirilebilirvec.reserve(sizeof...(Args))
Indiana Kernick

1
@alain operator=kaynağı yok etmez. Bu kopya-takas deyimidir.
Ocak'ta yeniden bağlan

Yanıtlar:


11

Std :: vector ... birleştirebilir miyim

Hayır. std::vectorBir toplu değil, bu nedenle toplu olarak başlatılamaz.

Bunun yerine liste başlatma anlamına gelebilir, bu durumda:

Can I [liste başlatma işlemini] std :: elemanlarının kusursuz yönlendirme ile vektör?

Hayır. Liste başlatma, yapıcıyı kullanır std::initializer_listve std::initializer_listbağımsız değişkenlerini kopyalar.

Sizin init_emplace_vectoro elemanlarının yerlerine yerleştirmelerine önce hafızada yer geliştirilebilir rağmen görünür, iyi bir çözüm gibi.


1
Beni düzelttiğin için teşekkürler. Editted. Rezerv ile iyi bir nokta.
Ocak'ta yeniden bağlan
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.