นี่เป็นคำถามที่เก่าแล้วตอบ แต่ @Alexandre ถามว่า "ทำไมทุกคนต้องการทำเช่นนี้" และฉันคิดว่าฉันอาจให้ตัวอย่างการใช้งานที่ฉันกำลังพิจารณาในบ่ายนี้
รหัสดั้งเดิม ใช้ตัวชี้เปล่า ๆ Obj * obj ด้วยการลบ obj ในตอนท้าย
น่าเสียดายที่บางครั้งฉันต้องการไม่บ่อยครั้งเพื่อให้วัตถุมีชีวิตอยู่อีกต่อไป
ฉันกำลังพิจารณาทำให้เป็นตัวชี้สมาร์ทการอ้างอิงนับ แต่จะมีรหัสมากมายที่จะเปลี่ยนถ้าฉันต้องใช้ref_cnt_ptr<Obj>
ทุกที่ และถ้าคุณผสม Obj * เปล่าและ ref_cnt_ptr คุณสามารถลบวัตถุโดยปริยายเมื่อ ref_cnt_ptr สุดท้ายหายไปแม้ว่าจะมี Obj * ยังมีชีวิตอยู่
ดังนั้นฉันกำลังคิดเกี่ยวกับการสร้างชัดเจน _elete_ref_cnt_ptr คือตัวชี้นับที่อ้างอิงซึ่งการลบจะกระทำในรูทีนการลบอย่างชัดเจนเท่านั้น ใช้งานในที่เดียวที่โค้ดที่มีอยู่รู้อายุการใช้งานของวัตถุรวมถึงในรหัสใหม่ของฉันที่ทำให้วัตถุมีอายุการใช้งานยาวนานขึ้น
การเพิ่มและลดจำนวนการอ้างอิงที่ชัดเจนได้รับการจัดการ _ref_cnt_ptr
แต่ไม่ว่างเมื่อจำนวนการอ้างอิงถูกเห็นว่าเป็นศูนย์ใน destructor ชัดเจน_delete_ref_cnt_ptr
การทำให้ว่างเท่านั้นเมื่อการนับการอ้างอิงถูกเห็นว่าเป็นศูนย์ในการดำเนินการลบอย่างชัดเจน เช่นในสิ่งที่ชอบ:
template<typename T> class explicit_delete_ref_cnt_ptr {
private:
T* ptr;
int rc;
...
public:
void delete_if_rc0() {
if( this->ptr ) {
this->rc--;
if( this->rc == 0 ) {
delete this->ptr;
}
this->ptr = 0;
}
}
};
ตกลงบางอย่างเช่นนั้น มันผิดปกติเล็กน้อยที่จะมีการนับประเภทตัวชี้การอ้างอิงไม่ลบวัตถุที่ชี้ไปในตัวทำลาย ptr ของ rc'ed โดยอัตโนมัติ แต่ดูเหมือนว่าสิ่งนี้อาจทำให้การผสมพอยน์เตอร์พอยน์เตอร์และพอยน์เตอร์ rc'ed ปลอดภัยขึ้นเล็กน้อย
แต่จนถึงตอนนี้ไม่จำเป็นต้องลบสิ่งนี้
แต่มันเกิดขึ้นกับฉัน: ถ้าวัตถุชี้ไปที่ Pointee รู้ว่ามันกำลังถูกนับการอ้างอิงเช่นถ้าการนับอยู่ภายในวัตถุ (หรือในตารางอื่น ๆ ) แล้ว delete_if_rc0 ประจำอาจเป็นวิธีการของ วัตถุ pointee ไม่ใช่ตัวชี้ (สมาร์ท)
class Pointee {
private:
int rc;
...
public:
void delete_if_rc0() {
this->rc--;
if( this->rc == 0 ) {
delete this;
}
}
}
};
จริงๆแล้วมันไม่จำเป็นต้องเป็นวิธีสมาชิกเลย แต่อาจเป็นฟังก์ชั่นฟรี:
map<void*,int> keepalive_map;
template<typename T>
void delete_if_rc0(T*ptr) {
void* tptr = (void*)ptr;
if( keepalive_map[tptr] == 1 ) {
delete ptr;
}
};
(BTW ฉันรู้ว่ารหัสไม่ถูกต้อง - มันจะอ่านได้น้อยลงถ้าฉันเพิ่มรายละเอียดทั้งหมดดังนั้นฉันจะปล่อยให้มันเป็นแบบนี้)
delete this
คุณสร้างข้อต่อแน่นระหว่างคลาสและวิธีการจัดสรรที่ใช้สำหรับสร้างวัตถุของคลาสนั้น นั่นคือการออกแบบ OO ที่แย่มากเนื่องจากสิ่งพื้นฐานที่สุดใน OOP คือการสร้างคลาสของตนเองซึ่งไม่ทราบหรือสนใจว่าผู้โทรทำอะไร ดังนั้นคลาสที่ออกแบบมาอย่างเหมาะสมไม่ควรรู้หรือสนใจว่ามันถูกจัดสรรอย่างไร หากคุณมีเหตุผลบางอย่างที่ต้องการกลไกแปลกประหลาดฉันคิดว่าการออกแบบที่ดีกว่าคือการใช้คลาส wrapper รอบคลาสจริงและปล่อยให้ wrapper จัดการกับการจัดสรร