Đây là một câu hỏi cũ, đã được trả lời, nhưng @Alexandre đã hỏi "Tại sao mọi người muốn làm điều này?", Và tôi nghĩ rằng tôi có thể cung cấp một ví dụ sử dụng mà tôi đang xem xét chiều nay.
Mã di sản. Sử dụng con trỏ trần Obj * obj với một obj xóa ở cuối.
Thật không may, đôi khi tôi cần, không thường xuyên, để giữ cho đối tượng sống lâu hơn.
Tôi đang xem xét làm cho nó một tham chiếu đếm con trỏ thông minh. Nhưng sẽ có rất nhiều mã để thay đổi, nếu tôi sử dụngref_cnt_ptr<Obj>
ở mọi nơi. Và nếu bạn trộn Obj * và ref_cnt_ptr trần trụi, bạn có thể khiến đối tượng bị xóa hoàn toàn khi ref_cnt_ptr cuối cùng biến mất, mặc dù vẫn còn Obj *.
Vì vậy, tôi đang suy nghĩ về việc tạo một tệp_d_deteetefff_cnt_ptr. Tức là một con trỏ đếm tham chiếu trong đó việc xóa chỉ được thực hiện trong một thói quen xóa rõ ràng. Sử dụng nó ở một nơi mà mã hiện có biết thời gian tồn tại của đối tượng, cũng như trong mã mới của tôi giúp đối tượng tồn tại lâu hơn.
Tăng và giảm số tham chiếu là tường minh_bảng_fete_fr_ptr bị thao túng.
Nhưng KHÔNG giải phóng khi số tham chiếu được xem là bằng 0 trong hàm hủy tường minh_delete_Vf_cnt_ptr.
Chỉ giải phóng khi số tham chiếu được xem là 0 trong một hoạt động giống như xóa rõ ràng. Ví dụ như trong một cái gì đó như:
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;
}
}
};
OK, một cái gì đó như thế. Có một chút khác thường khi có một loại con trỏ đếm tham chiếu không tự động xóa đối tượng được trỏ đến trong hàm hủy ptr của RC. Nhưng có vẻ như điều này có thể làm cho việc trộn con trỏ trần và con trỏ RC an toàn hơn một chút.
Nhưng cho đến nay không cần phải xóa điều này.
Nhưng sau đó nó đã xảy ra với tôi: nếu đối tượng được trỏ đến, pointee, biết rằng nó đang được tham chiếu, ví dụ nếu số đếm nằm trong đối tượng (hoặc trong một số bảng khác), thì thường trình xóa_if_rc0 có thể là một phương thức của đối tượng pointee, không phải con trỏ (thông minh).
class Pointee {
private:
int rc;
...
public:
void delete_if_rc0() {
this->rc--;
if( this->rc == 0 ) {
delete this;
}
}
}
};
Trên thực tế, nó không cần phải là một phương thức thành viên, nhưng có thể là một chức năng miễn phí:
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, tôi biết mã không hoàn toàn đúng - nó trở nên ít đọc hơn nếu tôi thêm tất cả các chi tiết, vì vậy tôi sẽ để nó như thế này.)
delete this
đã tạo ra một khớp nối chặt chẽ giữa lớp và phương thức phân bổ được sử dụng để tạo các đối tượng của lớp đó. Đó là thiết kế OO rất kém, vì điều cơ bản nhất trong OOP là tạo ra các lớp tự trị mà không biết hoặc không quan tâm đến những gì người gọi của họ đang làm. Do đó, một lớp được thiết kế đúng không nên biết hoặc quan tâm đến cách phân bổ. Nếu bạn vì một lý do nào đó cần một cơ chế đặc biệt như vậy, tôi nghĩ rằng một thiết kế tốt hơn sẽ là sử dụng một lớp bao bọc xung quanh lớp thực tế và để cho trình bao bọc xử lý việc phân bổ.