2009-01-15 35 views
28

Hôm nay, tôi đã thấy một số mã cũ. Trong destructor có một tuyên bố như "delete this". Tôi nghĩ, cuộc gọi này sẽ được đệ quy. Tại sao nó hoạt động?Việc sử dụng "xóa mục này" là gì?

Tôi đã thực hiện một số tìm kiếm nhanh trên Y !, Tôi thấy rằng nếu có nhu cầu hạn chế người dùng tạo đối tượng ngăn xếp, chúng tôi có thể hủy riêng tư và cung cấp giao diện để xóa cá thể. Trong giao diện được cung cấp, chúng ta phải gọi xóa trên con trỏ này.

Có bất kỳ tình huống nào khác để sử dụng báo cáo như vậy không?

Trả lời

32

"xóa mục này" thường được sử dụng cho các đối tượng được tính ref. Đối với đối tượng được tính ref, quyết định xóa khi nào thường được đặt trên chính đối tượng đó. Đây là một ví dụ về phương thức Release sẽ trông như thế nào [1].

int MyRefCountedObject::Release() { 
    _refCount--; 
    if (0 == _refCount) { 
    delete this; 
    return 0; 
    } 
    return _refCount; 
} 

Đối tượng ATL COM là ví dụ điển hình của mẫu này.

[1] Có, tôi nhận thấy đây không phải là chủ đề an toàn.

+0

Trong khi tự xóa đối tượng được đếm lại là một mẫu rất phổ biến, tôi nghĩ câu hỏi ban đầu là đặt nó vào một hàm hủy, chứ không phải hàm Release(), trong trường hợp đó nó chỉ là điên. – rmeador

+0

@rmeador, Có hai câu hỏi thực sự. Cả hai tiêu đề và câu cuối cùng đề nghị muốn biết sử dụng hợp lệ của "xóa này;". Tôi hy vọng tôi đã trả lời điều đó. Giữa không đề xuất một câu hỏi "tại sao xóa điều này trong một dtor". Tôi đồng ý làm như vậy có vẻ điên rồ. – JaredPar

+10

Mã mẫu của bạn có lỗi. Nếu _refCount là biến thành viên, khi bạn "xóa" biến thành viên đó không còn tồn tại, do đó, dòng "return _refCount" của bạn có hành vi không xác định. – ChrisN

24

delete this không hợp lệ trong trình phá hủy. Nó có thể được sử dụng ở nơi khác. Nhưng nó hiếm khi là một ý tưởng hay. Khung công tác wxWidgets sử dụng nó cho lớp chuỗi của chúng. Nó có một chế độ trong đó, khi luồng kết thúc thực hiện, nó sẽ tự động giải phóng tài nguyên hệ thống và chính nó (đối tượng wxThread). Tôi thấy nó rất khó chịu, bởi vì từ bên ngoài, bạn không thể biết liệu nó có hợp lệ để tham khảo hay không - bạn không thể gọi một hàm như IsValid nữa, bởi vì đối tượng không tồn tại. Điều đó có mùi giống như vấn đề chính với delete this, ngoài vấn đề là nó không thể được sử dụng cho các đối tượng không động.

Nếu bạn làm điều đó, hãy đảm bảo bạn không chạm vào bất kỳ thành viên dữ liệu nào hoặc gọi bất kỳ chức năng thành viên nào nữa trên đối tượng bạn đã xóa theo cách đó. Tốt nhất làm điều đó như là câu lệnh cuối cùng trong một hàm không phải ảo, được bảo vệ hoặc riêng tư. Gọi xóa là hợp lệ trong một chức năng ảo và/hoặc công cộng quá, nhưng tôi sẽ hạn chế khả năng hiển thị của phương pháp làm điều đó.

C++ FAQ có mục nhập về điều đó. Trích dẫn C++ Standard trên xác nhận quyền sở hữu của tôi ở trên (3.8p5):

Trước khi lưu trữ đối tượng đã được cấp phát hoặc sau khi hết thời gian của đối tượng đã kết thúc và trước lưu trữ mà đối tượng bị chiếm đóng được tái sử dụng hoặc phát hành, bất kỳ con trỏ nào đề cập đến vị trí lưu trữ nơi đối tượng sẽ được định vị hoặc được định vị có thể được sử dụng nhưng chỉ theo những cách hạn chế. [...] Nếu đối tượng sẽ là hoặc thuộc loại lớp với trình phá hủy không tầm thường và con trỏ được sử dụng làm toán hạng của biểu thức xóa, chương trình có hành vi không xác định.

Thời gian kết thúc khi trình phá hủy của đối tượng bắt đầu thực thi. Lưu ý có những ngoại lệ đối với các quy tắc đến sau đoạn đó đối với các đối tượng đang được xây dựng và phá hủy (ví dụ bạn được phép truy cập các thành viên dữ liệu không tĩnh), chi tiết tại 12.7.

3

Có nơi được coi là lý do chính đáng để thực hiện việc này trong những ngày C++ đầu. Ví dụ như tự xóa của một đối tượng được tính ref (như JaredPar nói). Theo như tôi biết, tất cả chúng đều được tìm thấy là một ý tưởng tồi trong thời gian dài.

+0

chính xác những gì tôi nghĩ. ngày hôm nay nếu tôi cần viết một đối tượng được tính ref, tôi sẽ giữ dữ liệu trong một đối tượng thừa và tạo đối tượng host (đối tượng được sao chép xung quanh) xóa dữ liệu được bao bọc khi số tham chiếu giảm xuống 0. tự xóa mùi :) –

+0

@Johannes Schaub - litb: Hoàn toàn đồng ý; một đối tượng chịu trách nhiệm về trách nhiệm của mình và quyết định khi nào nên tự dọn dẹp? Yucky! – jason

+1

@ JohannesSchaub-litb sau đó đối tượng lưu trữ phải tự xóa khi được thực hiện thay thế ... –

2

Trong danh sách được liên kết kép, bạn có thể xóa nút mà không tham chiếu bất kỳ cấu trúc bên ngoài nào, chẳng hạn như đối tượng "danh sách" cấp cao. Điều này làm cho nó hợp lý cho mỗi nút để xử lý deallocation của riêng nó (có khả năng kết hợp với một phương thức tĩnh bổ sung để xử lý việc cấp phát ban đầu từ cùng một bộ nhớ). Trong tình huống này, nó có thể có ý nghĩa đối với đối tượng nút để xóa chính nó (khi được yêu cầu bởi người dùng).

void RemoveAndDeallocate() 
{ 
    LinkedListNode *current_prev = prev, *current_next = next; 
    current_prev->next = current_next; 
    current_next->prev = current_prev; 
    delete this; 
} 

Mặc dù, nó cũng hợp lý cho một nút để hủy liên kết từ một danh sách và liên kết vào danh sách khác, mà không deallocating bất kỳ bộ nhớ, vì vậy nó không mong muốn cho một hoạt động remove duy nhất để vô điều kiện giải phóng bộ nhớ.

Các vấn đề liên quan