2010-10-18 23 views
9

Mã sau đây được biên dịch bằng MSVC9.0 chạy và xuất ra Destructor bốn lần, hợp lý.Tự sát hướng đối tượng hoặc xóa điều này;

#include <iostream> 
class SomeClass 
{ 
public: 
    void CommitSuicide() 
    { 
     delete this; 
    } 
    void Reincarnate() 
    { 
     this->~SomeClass(); 
     new (this) SomeClass; 
    } 
    ~SomeClass() 
    { 
     std::cout << "Destructor\n"; 
    } 
}; 

int main() 
{ 
    SomeClass* p = new SomeClass; 
    p->CommitSuicide(); 
    p = new SomeClass; 
    p->Reincarnate(); 
    p->~SomeClass(); //line 5 
    p->CommitSuicide(); 
} 

Tôi nghĩ rằng 4 dòng đầu tiên của mã không chính xác dẫn đến hành vi không xác định (mặc dù không hoàn toàn chắc chắn về điều delete this;). Tôi muốn có xác nhận hoặc < trình giữ chỗ cho từ trái nghĩa của xác nhận> trong số đó. Nhưng tôi có những nghi ngờ nghiêm trọng về dòng 5 và 6. Nó được phép gọi một cách rõ ràng destructor, phải không? Nhưng liệu cuộc đời của đối tượng được coi là đã kết thúc sau đó? Đó là, là lời gọi của một thành viên khác sau khi cuộc gọi rõ ràng của destructor cho phép (được xác định)?

Để tóm tắt, các phần nào của mã trên (nếu có) dẫn đến hành vi không xác định (nói kỹ thuật)?

+0

Nhưng hàm tạo chỉ được gọi là 3 lần, vậy làm thế nào để gọi hàm hủy 4 lần hợp lý? Nó sẽ đánh bom ngay khi lớp học trở thành thành viên dữ liệu (không tầm thường). – visitor

+0

- nó được gọi là "từ chối" – slashmais

Trả lời

2

p-> ~ SomeClass(); // line 5

p-> CommitSuicide(); // line 6

Dòng (6) chắc chắn gọi hành vi không xác định.

Tức là, là yêu cầu của một thành viên khác sau khi cuộc gọi rõ ràng của destructor được cho phép (được xác định)?

Không! Giả định của bạn là chính xác.

+0

dòng 6 "nên" cung cấp cho một lỗi truy cập bộ nhớ (segfault trên linux) vì không gian địa chỉ trước đây chiếm đóng bởi thể hiện của SomeClass trỏ đến bởi p, "nên" đã được giải phóng đúng cách bởi hệ điều hành. Hoặc không destructor làm một cuộc gọi muộn để xóa? – slashmais

+0

@slashmais: Không, không có bảo đảm như vậy, và rất ít triển khai hoạt động như thế. Hầu hết các triển khai có khái niệm "không gian trống", là bộ nhớ được hệ điều hành cấp cho chương trình, nhưng không chứa bất kỳ đối tượng nào. Bộ nhớ lấy lại từ các đối tượng đã xóa được tái chế vào "không gian trống" này, được sử dụng bởi các đối tượng trong tương lai. – MSalters

+0

Vâng, tôi nghĩ rằng nó sẽ là một cái gì đó như thế. Giải thích dòng 6 thành công sau đó vì không gian chưa được tái chế. – slashmais

6

delete this; là tiền phạt. Cuối cùng p->CommitSuicide(); cho hành vi không xác định vì bạn đã phá hủy đối tượng trong "dòng 5".

0

"xóa này" là ok miễn là bạn không cố gọi bất kỳ mã nào của đối tượng đó sau khi xóa (thậm chí không phải là phá hủy). Vì vậy, một đối tượng tự xóa shoud chỉ được đặt ở heap và shoud có một destructor riêng để bảo vệ từ sáng tạo trên stack.

Tôi không biết liệu cuộc gọi trực tiếp đến trình phá hủy có dẫn đến hành vi không xác định hay không nhưng một người dùng xóa do người dùng xác định sẽ không được thực thi.

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