2013-05-02 39 views
9

Vì vậy, trong ví dụ sau, chúng tôi gây ra lớp Foo để thay thế chính nó bằng *this = Foo(). Tôi rất vui vì tôi đã thử nghiệm điều này bởi vì nó quay ra trong trường hợp này, các destructor của cũ Foo không nhận được gọi. Tôi đoán đó là vì toán tử gán mặc định chỉ sử dụng memcpy ... nhưng là câu hỏi thiết kế ngôn ngữ ... tại sao bạn không làm toán tử gán mặc định hủy đối tượng được gán trước để ngăn ngừa tai nạn?Tại sao toán tử gán mặc định không gọi hàm hủy trước?

http://codepad.org/9WCo6yZ5

#include <iostream> 
using namespace std; 

class MustBeDestroyed //(for some reason not shown here) 
{ 
public: 
    int i; 
    MustBeDestroyed(int i) : i(i) {} 
    ~MustBeDestroyed() { cout << "destroyed contained class " << i << endl; } 
}; 

class Foo 
{ 
public: 
    MustBeDestroyed x; 
    Foo(int y) : x(y) {} 
    void replace_myself(int y) { Foo f(y); *this=f; } 
    void print() { cout << "This is outer/inner class " << x.i << endl; } 
    ~Foo() { cout << "destroyed outer class " << x.i << endl; } 
}; 

int main() 
{ 
    Foo a(1); 
    a.print(); 
    a.replace_myself(2); 
    a.print(); 
    return 0; 
} 
+2

Tai nạn gì? Nhiệm vụ chỉ là - gán một giá trị mới cho một giá trị cũ. –

+1

Toán tử gán mặc định không sử dụng memcpy (mặc dù tối ưu hóa trình biên dịch có thể dẫn đến điều đó). Đó là một sự phân công theo từng người. – huskerchad

+1

'int i, j; i = 5; j = i; 'bạn đang nói rằng nó là hợp lý để mong đợi rằng tôi không thể sử dụng' i' nữa? Tôi không đồng ý. – Fiktik

Trả lời

1

Tại sao nhiệm vụ sẽ gọi destructor? Nó thực hiện chính xác những gì được nói nó: Nó gọi toán tử gán. Trình biên dịch tạo ra toán tử gán chỉ đơn giản là rõ ràng: gán tất cả các thành viên từ obejct cũ sang mới (sử dụng phép gán của chúng). Không hơn không kém. Đây chính là lý do cho số rule of three nổi tiếng.

Bây giờ là tại sao nó không gọi destructor: Điều đó sẽ kết thúc tuổi thọ của đối tượng. Mặc dù về lý thuyết có thể xây dựng một vật thể mới thay thế cho vật thể cũ, nhưng cách tiếp cận đó thường không chính xác khi đối mặt với ngoại lệ (look at this question for more about that), vì vậy nó không thể được sử dụng trong trường hợp chung. Bên cạnh đó nếu nó đã làm cách tiếp cận bạn đề xuất, nó sẽ không gọi các toán tử gán cho các thành viên, nhưng thay vào đó là hàm tạo destructor/copy. Điều đó có nghĩa rằng hành vi gán tùy chỉnh (không thực sự cần phải giống như hành vi sao chép) sẽ không được tôn trọng.

+1

Nhiệm vụ sẽ gọi cho destructor trước để tránh rò rỉ bộ nhớ nếu giá trị bị ghi đè chứa một ptr đến dữ liệu ngoài heap. Nếu bạn chỉ đơn giản là ghi đè lên ptr, sau đó bạn bị rò rỉ bộ nhớ. Do đó, toán tử gán được xây dựng trong nên được ghi đè trong trường hợp này (vì tích hợp sẽ bị rò rỉ). – wcochran

6

Bởi vì phá hủy các đối tượng đầu tiên sẽ kết thúc cuộc đời. Sau đó, bạn sẽ phải gọi một hàm tạo để bắt đầu tuổi thọ của đối tượng mới. Nhưng hành vi của toán tử = không phải là để hủy bỏ đối tượng hiện tại và tạo một đối tượng khác, nhưng gán một giá trị mới cho đối tượng hiện có.

Về cơ bản, bạn đã vi phạm nguyên tắc 3.

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