Chuyện gì đang xảy ra
Khi bạn viết T t;
bạn đang tạo một đối tượng loại T
có thời lượng lưu trữ tự động . Nó sẽ được làm sạch tự động khi đi ra khỏi phạm vi.
Khi bạn viết new T()
bạn đang tạo một đối tượng loại T
có thời lượng lưu trữ động . Nó sẽ không được làm sạch tự động.
Bạn cần chuyển một con trỏ tới nó delete
để dọn sạch nó:
Tuy nhiên, ví dụ thứ hai của bạn tệ hơn: bạn đang hủy bỏ con trỏ và tạo một bản sao của đối tượng. Bằng cách này, bạn mất con trỏ đến đối tượng được tạo new
, vì vậy bạn không bao giờ có thể xóa nó ngay cả khi bạn muốn!
Bạn nên làm gì
Bạn nên thích thời gian lưu trữ tự động. Cần một đối tượng mới, chỉ cần viết:
A a; // a new object of type A
B b; // a new object of type B
Nếu bạn cần thời lượng lưu trữ động, lưu trữ con trỏ đến đối tượng được phân bổ trong đối tượng thời lượng lưu trữ tự động sẽ tự động xóa nó.
template <typename T>
class automatic_pointer {
public:
automatic_pointer(T* pointer) : pointer(pointer) {}
// destructor: gets called upon cleanup
// in this case, we want to use delete
~automatic_pointer() { delete pointer; }
// emulate pointers!
// with this we can write *p
T& operator*() const { return *pointer; }
// and with this we can write p->f()
T* operator->() const { return pointer; }
private:
T* pointer;
// for this example, I'll just forbid copies
// a smarter class could deal with this some other way
automatic_pointer(automatic_pointer const&);
automatic_pointer& operator=(automatic_pointer const&);
};
automatic_pointer<A> a(new A()); // acts like a pointer, but deletes automatically
automatic_pointer<B> b(new B()); // acts like a pointer, but deletes automatically
Đây là một thành ngữ phổ biến đi theo tên không mô tả RAII ( Tài nguyên là khởi tạo tài nguyên ). Khi bạn có được một tài nguyên cần dọn dẹp, bạn sẽ gắn nó vào một đối tượng có thời lượng lưu trữ tự động để bạn không cần phải lo lắng về việc làm sạch nó. Điều này áp dụng cho bất kỳ tài nguyên nào, có thể là bộ nhớ, mở tệp, kết nối mạng hoặc bất cứ thứ gì bạn thích.
Điều này automatic_pointer
đã tồn tại dưới nhiều hình thức khác nhau, tôi vừa cung cấp nó để đưa ra một ví dụ. Một lớp rất giống tồn tại trong thư viện tiêu chuẩn được gọi std::unique_ptr
.
Cũng có một cái cũ (tiền C ++ 11) có tên auto_ptr
nhưng hiện tại nó không dùng nữa vì nó có hành vi sao chép lạ.
Và sau đó, có một số ví dụ thậm chí thông minh hơn, như std::shared_ptr
, cho phép nhiều con trỏ đến cùng một đối tượng và chỉ làm sạch nó khi con trỏ cuối cùng bị phá hủy.