Phương thức hủy đối tượng trong C++?

Khi làm quen với phần Lớp và Đối tượng trong C++, em thấy một số dạng bài tập yêu cầu đối số của object đưa vào constructor phải thỏa mãn điều kiện của đề. Vì vậy đối với những trường hợp object có đầu vào không hợp lệ thì cách em xử lí là gọi phương thức hủy object đó. Như vậy có hợp lí k ạ :> Hay mình nên đưa phần đối số không hợp lệ về giá trị mặc định của đề? Mà object có thực sự bị xóa sau khi hàm hủy được gọi không ạ? Em nghĩ phương thức hủy trong class nó giống với default: trong hàm case vậy mà không biết đúng k. Tại theo cách xử lí của em thì khi tới phần dữ liệu tĩnh, gặp mấy bài kiểu đếm số object hiện có đó, em phân vân mấy object được khai báo mà đầu vào không hợp lệ thì có đếm nó không? Tuy phương thức hủy được gọi nhưng object có đang tồn tại với giá trị thành viên chưa xác định?
Tại không cấp phát mảng động gì nên phương thức hủy của em nó thô sơ thế này. Có thừa k ạ hay nên để trình biên dịch hủy mặc định:

something::~something(void){};

Dữ liệu không hợp lệ thì quăng (throw) ngoại lệ ra bạn à. Đối tượng chỉ khỏi tạo thành công khi chạy xong hàm dựng (constructor) mà không gặp bất kì ngoại lệ nào. Bởi vậy, khi ngoại lệ được quăng ra thì nó sẽ không tồn tại đối tượng đó.

4 Likes

ko bao giờ gọi dtor trực tiếp nha :V Ít nhất 5 năm kinh nghiệm mới được phép gọi nha :V

lúc object đang khởi tạo mà ko khởi tạo thành công thì object đâu có được tạo ra đâu, ko cần gọi hàm hủy. Gọi hàm hủy có khi còn gây nguy hại hơn :V

“thực sự bị xóa” nghĩa là thế nào :V Nếu object ko cấp phát động gì ví dụ là struct { int32_t; int32_t; } chẳng hạn thì chả cần xóa nó gì cả, để nguyên giá trị ở đó cũng được, chỉ đánh dấu vùng nhớ 8 byte nó ko xài nữa là vùng nhớ ko có ai sử dụng là được. Giá trị cũ vẫn ở đó, khi nào có object khác xài vùng nhớ này nó ghi đè lên ko có vấn đề gì cả. Trừ phi làm bảo mật gì đấy thì có thể phải xóa giá trị cũ này bằng cách ghi đè lên giá trị ngẫu nhiên hoặc 0 hết chẳng hạn :V

không :V

thừa. Mặc định nó cũng bỏ trống thế thôi, mất công viết ra thêm dòng này làm gì.

em cho code cụ thể đi :V Người ta khuyên là nên ném ngoại lệ khi khởi tạo ko thành công. Mà cũng phải ném cẩn thận tránh leak memory nữa :V Tuy nhiên ở đây em ko cấp phát động gì thì có thể xài cách khác là nếu tham số ko hợp lệ thì khởi tạo 1 object “ma” vd bằng 1 biến bool hasValidStates, khổ cái mỗi lần khởi tạo xong thì phải ktra object đó có hợp lệ hay ko, vd

MyObject obj(...);
if (obj.isValid()) { /* tiếp tục */ }

// khổ cái nữa nếu code defensive thì mỗi hàm trong MyObject 
// cũng phải ktra object state trước khi thực hiện hàm đó:
void MyObject::func(...) {
    if (!isValid()) return;
    // ...
}
4 Likes

Bây giờ trong constructor vừa cấp phát bộ nhớ động rồi tạch thì sao nhỉ ?
Chắc có memory leak.

đúng là có leak, bởi vậy mới có lời khuyên là phải nhớ undo cấp phát trước khi throw: https://isocpp.org/wiki/faq/exceptions#selfcleaning-members

If a constructor throws an exception, the object’s destructor is not run. If your object has already done something that needs to be undone (such as allocating some memory, opening a file, or locking a semaphore), this “stuff that needs to be undone” must be remembered by a data member inside the object.

hay tốt hơn là xài smart pointers chứ ko xài raw ptr nữa thì throw thoải mái ko cần nhớ phải undo

struct Foo {
  int* rawPtr1;
  int* rawPtr2;
  Foo::Foo()
  : rawPtr1(new int),
  , rawPtr2(new int) // lỡ có lỗi xảy ra ở đây thì rawPtr1 ko được giải phóng 
  {}
};

struct Foo {
  std::unique_ptr<int> uptr1;
  std::unique_ptr<int> uptr2;
  Foo::Foo()
  : uptr1(std::make_unique<int>()),
  , uptr2(std::make_unique<int>()) // lỡ có lỗi xảy ra ở đây thì bảo đảm sẽ gọi dtor của uptr1
  {}
};
4 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?