ฉันต้องการคอนเทนเนอร์ C++ ที่มีข้อกำหนดต่อไปนี้:
- คอนเทนเนอร์สามารถจัดเก็บวัตถุที่ไม่สามารถคัดลอกและไม่สามารถเคลื่อนย้ายได้ในหน่วยความจำต่อเนื่อง สำหรับ
std::vector
วัตถุจะต้องคัดลอกหรือเคลื่อนย้ายได้ capacity
ของคอนเทนเนอร์เป็นที่รู้จักในระหว่างการก่อสร้าง ณ รันไทม์ และคงที่จนกว่าจะถูกทำลาย พื้นที่หน่วยความจำที่จำเป็นทั้งหมดได้รับการจัดสรรระหว่างการก่อสร้าง สำหรับboost::static_vector
ทราบความจุ ณ เวลาคอมไพล์- ขนาดของคอนเทนเนอร์สามารถเพิ่มขึ้นเมื่อเวลาผ่านไปเมื่อมีองค์ประกอบเพิ่มขึ้น
emplace_back
รายการในคอนเทนเนอร์ แต่ไม่ควรเกินcapacity
- เนื่องจากวัตถุไม่สามารถคัดลอกหรือเคลื่อนย้ายได้ จึงไม่อนุญาตให้มีการจัดสรรใหม่
ดูเหมือนว่าทั้ง STL และ BOOST ไม่มีประเภทคอนเทนเนอร์ที่ฉันต้องการ ฉันได้ค้นหาในด้านนี้อย่างกว้างขวางแต่ไม่พบคำตอบ ดังนั้นฉันจึงได้ดำเนินการอย่างใดอย่างหนึ่ง
#include <memory>
template<class T>
class FixedCapacityVector {
private:
using StorageType = std::aligned_storage_t<sizeof(T), alignof(T)>;
static_assert(sizeof(StorageType) == sizeof(T));
public:
FixedCapacityVector(FixedCapacityVector const&) = delete;
FixedCapacityVector& operator=(FixedCapacityVector const&) = delete;
FixedCapacityVector(size_t capacity = 0):
capacity_{ capacity },
data_{ std::make_unique<StorageType[]>(capacity) }
{ }
~FixedCapacityVector()
{
for (size_t i = 0; i < size_; i++)
reinterpret_cast<T&>(data_[i]).~T();
}
template<class... Args>
T& emplace_back(Args&&... args)
{
if (size_ == capacity_)
throw std::bad_alloc{};
new (&data_[size_]) T{ std::forward<Args>(args)... };
return reinterpret_cast<T&>(data_[size_++]);
}
T& operator[](size_t i)
{ return reinterpret_cast<T&>(data_[i]); }
T const& operator[](size_t i) const
{ return reinterpret_cast<T const&>(data_[i]); }
size_t size() const { return size_; }
size_t capacity() const { return capacity_; }
T* data() { return reinterpret_cast<T*>(data_.get()); }
T const* data() const { return reinterpret_cast<T const*>(data_.get()); }
private:
size_t const capacity_;
std::unique_ptr<StorageType[]> const data_;
size_t size_{ 0 };
};
คำถามของฉันคือ:
- ทำไมฉันถึงทำเช่นนี้ด้วยมือ? ฉันไม่พบภาชนะมาตรฐาน หรือบางทีฉันอาจไม่ได้ดูที่ที่ถูกต้อง? หรือเพราะสิ่งที่ฉันพยายามทำนั้นไม่ธรรมดา?
- มีการใช้คอนเทนเนอร์ที่เขียนด้วยลายมือถูกต้องหรือไม่ แล้วความปลอดภัยของข้อยกเว้น ความปลอดภัยของหน่วยความจำ ฯลฯ ล่ะ?
std::shared_ptr
แล้วstd::shared_ptr
จะถูกเก็บไว้ในstd::vector
ได้หรือไม่ - person Eljay   schedule 26.12.2018std::vector<std::unique_ptr>
) บางทีฉันไม่ควรพูดประเภทคอนเทนเนอร์ที่จำเป็นโดยทั่วไปเช่นนี้ - person Tony Xiang   schedule 26.12.2018std::vector
ที่ปรับขนาดให้เหลือขนาดสูงสุดที่ต้องการ และติดตามว่ามีองค์ประกอบที่ใช้งานอยู่กี่องค์ประกอบ? หากเวกเตอร์นั้นเป็นสมาชิกส่วนตัวของชั้นเรียนของคุณ คุณสามารถมั่นใจได้ว่าจะไม่ปรับขนาดหลังจากการกำหนดค่าเริ่มต้น ไม่ว่าผู้ใช้ในชั้นเรียนของคุณจะทำอะไรก็ตาม ท้ายที่สุดแล้ว แม้ว่าผู้ใช้จะขอให้คลาสของคุณทำอะไรสักอย่างemplace_back()
คลาสของคุณ (หรือการนำฟังก์ชันสมาชิกของคลาสไปใช้งาน) ก็ไม่จำเป็นต้องเปลี่ยนสิ่งนั้นเป็นการเรียกemplace_back()
ของเวกเตอร์ - person Peter   schedule 26.12.2018std::vector<T>
จะไม่คอมไพล์หากT
ไม่สามารถคัดลอกและเคลื่อนย้ายไม่ได้ - person Tony Xiang   schedule 26.12.2018p->~T()
ถูกต้องหากp
เป็นตัวชี้ไปยังT
ที่ไม่ถูกทำลาย) อย่างไรก็ตาม คุณต้องระมัดระวังในการเลือกการดำเนินการกับเวกเตอร์ เนื่องจากฟังก์ชันสมาชิกของstd::vector
บางฟังก์ชันมีข้อกำหนดที่เข้มงวดกว่า (เช่น [จากหน่วยความจำ] เวกเตอร์emplace()
กำหนดให้องค์ประกอบต่างๆ เป็นแบบ Move Assignable, Move Insertable และ Emplace Constructible - เนื่องจากแตกต่างจากการคัดลอก มอบหมายและคัดลอกได้) - person Peter   schedule 26.12.2018std::vector<T>
สำหรับT
ที่ไม่สามารถคัดลอกได้-ไม่สามารถเคลื่อนย้ายได้ ดังที่คุณกล่าวไว้ อินสแตนซ์นั้นสามารถรวบรวมได้ อย่างไรก็ตาม ไม่สามารถใช้วิธีใดเพื่อเพิ่มองค์ประกอบให้กับเวกเตอร์ได้ ฉันคิดว่าemplace_back
สามารถใช้ได้เนื่องจากไม่จำเป็นต้องคัดลอกหรือย้ายหากไม่จำเป็นต้องจัดสรรใหม่ แต่คอมไพเลอร์ยังคงบ่นว่าตัวสร้างสำเนาที่ถูกลบไปแล้ว คุณมีความคิดวิธีการเพิ่มองค์ประกอบให้กับเวกเตอร์ในกรณีนี้หรือไม่? - person Tony Xiang   schedule 26.12.2018