การจัดสรรแบบไดนามิกจำเป็นเฉพาะเมื่ออายุการใช้งานของวัตถุควรแตกต่างจากขอบเขตที่ได้รับการสร้างขึ้น (ซึ่งถือเป็นอย่างดีสำหรับการทำให้ขอบเขตมีขนาดเล็กลงเป็นขนาดใหญ่กว่า) และคุณมีเหตุผลเฉพาะที่การจัดเก็บค่า งาน.
ตัวอย่างเช่น:
std::vector<int> *createVector(); // Bad
std::vector<int> createVector(); // Good
auto v = new std::vector<int>(); // Bad
auto result = calculate(/*optional output = */ v);
auto v = std::vector<int>(); // Good
auto result = calculate(/*optional output = */ &v);
ตั้งแต่ C ++ 11 เป็นต้นไปเรามีstd::unique_ptr
การจัดการกับหน่วยความจำที่จัดสรรซึ่งมีความเป็นเจ้าของหน่วยความจำที่จัดสรร std::shared_ptr
ถูกสร้างขึ้นเมื่อคุณต้องแบ่งปันความเป็นเจ้าของ (คุณต้องใช้โปรแกรมนี้น้อยกว่าที่คาดไว้ในโปรแกรมที่ดี)
การสร้างตัวอย่างนั้นง่ายมาก:
auto instance = std::make_unique<Class>(/*args*/); // C++14
auto instance = std::make_unique<Class>(new Class(/*args*/)); // C++11
auto instance = std::make_unique<Class[]>(42); // C++14
auto instance = std::make_unique<Class[]>(new Class[](42)); // C++11
C ++ 17 ยังเพิ่มstd::optional
สิ่งที่ป้องกันไม่ให้คุณต้องการการจัดสรรหน่วยความจำ
auto optInstance = std::optional<Class>{};
if (condition)
optInstance = Class{};
ทันทีที่ 'อินสแตนซ์' ไม่อยู่ในขอบเขตหน่วยความจำก็จะถูกกำจัด การโอนความเป็นเจ้าของเป็นเรื่องง่าย:
auto vector = std::vector<std::unique_ptr<Interface>>{};
auto instance = std::make_unique<Class>();
vector.push_back(std::move(instance)); // std::move -> transfer (most of the time)
ดังนั้นเมื่อใดที่คุณยังคงต้องnew
? แทบไม่เคยมาจาก C ++ 11 ส่วนใหญ่คุณใช้std::make_unique
จนกว่าจะถึงจุดที่คุณตี API ที่โอนความเป็นเจ้าของผ่านตัวชี้ดิบ
auto instance = std::make_unique<Class>();
legacyFunction(instance.release()); // Ownership being transferred
auto instance = std::unique_ptr<Class>{legacyFunction()}; // Ownership being captured in unique_ptr
ใน C ++ 98/03 คุณต้องจัดการหน่วยความจำด้วยตนเอง หากคุณอยู่ในกรณีนี้ให้ลองอัปเกรดเป็นรุ่นที่ใหม่กว่าของมาตรฐาน หากคุณติดขัด:
auto instance = new Class(); // Allocate memory
delete instance; // Deallocate
auto instances = new Class[42](); // Allocate memory
delete[] instances; // Deallocate
ตรวจสอบให้แน่ใจว่าคุณติดตามความเป็นเจ้าของอย่างถูกต้องเพื่อไม่ให้มีหน่วยความจำรั่ว! ซีแมนทิกส์ย้ายยังไม่ทำงาน
ดังนั้นเมื่อไหร่ที่เราต้องการ malloc ใน C ++ เหตุผลที่ถูกต้องเพียงอย่างเดียวคือการจัดสรรหน่วยความจำและเตรียมใช้งานในภายหลังผ่านตำแหน่งใหม่
auto instanceBlob = std::malloc(sizeof(Class)); // Allocate memory
auto instance = new(instanceBlob)Class{}; // Initialize via constructor
instance.~Class(); // Destroy via destructor
std::free(instanceBlob); // Deallocate the memory
แม้ว่าข้างต้นจะถูกต้อง แต่ก็สามารถทำได้ผ่านตัวดำเนินการใหม่เช่นกัน std::vector
เป็นตัวอย่างที่ดีสำหรับสิ่งนี้
สุดท้ายเรายังมีช้างอยู่ในห้อง: C
. หากคุณต้องทำงานกับ C-library ซึ่งหน่วยความจำได้รับการจัดสรรในรหัส C ++ และปลดปล่อยในรหัส C (หรือวิธีอื่น ๆ ) คุณจำเป็นต้องใช้ malloc / free
หากคุณอยู่ในกรณีนี้ลืมเกี่ยวกับฟังก์ชั่นเสมือนฟังก์ชั่นสมาชิกคลาส ... อนุญาตให้ใช้กับ PODs ที่มี POD เท่านั้น
ข้อยกเว้นบางประการสำหรับกฎ:
- คุณกำลังเขียนไลบรารีมาตรฐานที่มีโครงสร้างข้อมูลขั้นสูงที่ malloc เหมาะสม
- คุณต้องจัดสรรหน่วยความจำจำนวนมาก (ในหน่วยความจำของไฟล์ 10GB?)
- คุณมีเครื่องมือที่ป้องกันไม่ให้คุณใช้โครงสร้างบางอย่าง
- คุณต้องจัดเก็บประเภทที่ไม่สมบูรณ์