ฉันสามารถ list-initialize std :: vector พร้อมการส่งต่อองค์ประกอบที่สมบูรณ์ได้หรือไม่?


14

ฉันสังเกตเห็นว่ารายการรวม initalization ของ std :: vector ดำเนินการเริ่มต้นการคัดลอกเมื่อย้ายจะใช้งานได้มากขึ้น ในเวลาเดียวกันหลาย emplace_backs ทำสิ่งที่ฉันต้องการ

init_emplace_vectorฉันเท่านั้นที่สามารถเกิดขึ้นกับวิธีการแก้ปัญหาที่ไม่สมบูรณ์ของการเขียนฟังก์ชั่นแม่แบบ มันเป็นสิ่งที่ดีที่สุดสำหรับตัวสร้างค่าเดียวที่ไม่ชัดเจน

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

คำถาม

ฉันจำเป็นต้องใช้ emplace_backเพื่อเริ่มต้น std :: vector ให้มีประสิทธิภาพมากที่สุดหรือไม่

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

เอาท์พุต

คลาสlargeผลิตข้อมูลเกี่ยวกับการคัดลอก / ย้าย (การนำไปใช้ด้านล่าง) และผลลัพธ์ของโปรแกรมของฉันคือ:

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

การใช้งานระดับใหญ่

การนำไปใช้ของฉันlargeเป็นเพียงประเภทที่คัดลอก / เคลื่อนย้ายได้ซึ่งถือทรัพยากรขนาดใหญ่ที่เตือนการคัดลอก / ย้าย

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

แก้ไข

โดยใช้การสำรองไม่มีการคัดลอกหรือย้าย คอนlarge::large(std::size_t)สตรัคเท่านั้นที่ถูกเรียก True emplace


1
std::initializer_listมันไม่ได้รวม-เริ่มต้นคุณจะโทรสร้างที่ใช้
ซุปเปอร์

std :: constructors ของ vector นั้นยุ่งเหยิง IMHO และถ้าฉันเป็นคุณฉันจะหลีกเลี่ยงไม่ให้เข้าไปถ้าไม่จำเป็นจริงๆ Plus ถ้าคุณรู้ว่าคุณเนื้อหาเวกเตอร์ล่วงหน้า (ซึ่งดูเหมือนว่ามันอาจจะมีกรณี) - std::arrayพิจารณา
einpoklum

1
สิ่งoperator=ที่ทำลายแหล่งกำเนิดนั้นค่อนข้างแปลกและอาจทำให้เกิดปัญหาที่ไม่คาดคิด
Alain

1
init_emplace_vectorสามารถปรับปรุงได้ด้วยvec.reserve(sizeof...(Args))
Indiana Kernick

1
@alain operator=ไม่ทำลายแหล่งที่มา มันเป็นสำนวนการแลกเปลี่ยน
สร้างใหม่

คำตอบ:


11

ฉันสามารถรวม - เริ่มต้น std :: vector ...

ไม่ใช่std::vectorไม่ใช่ผลรวมดังนั้นจึงไม่สามารถเริ่มต้นรวมได้

คุณอาจหมายถึง list-initialisation แทนซึ่งในกรณีนี้:

ฉันสามารถ[list-initialise] std :: vector พร้อมการส่งต่อองค์ประกอบที่สมบูรณ์แบบได้หรือไม่?

ไม่รายการเริ่มต้นใช้ตัวstd::initializer_listสร้างและstd::initializer_listคัดลอกอาร์กิวเมนต์

init_emplace_vectorดูเหมือนว่าคุณจะเป็นทางออกที่ดี แต่ก็สามารถปรับปรุงได้โดยการจองหน่วยความจำก่อนที่จะวางองค์ประกอบ


1
ขอบคุณสำหรับการแก้ไขฉัน editted จุดที่ดีกับสำรอง
สร้างใหม่
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.