30/09/2018, 18:22

Vì sao khi return *this chương trình lại tự gọi destructor?

Đây là code: http://codepad.org/pgOIaMIL

#include <iostream>
using namespace std;

class ClassA
{
	int *a;
public:
	ClassA()
	{
		a = new int[1];
		a[0] = 1;
	}

	ClassA abc()
	{
		return *this;
	}

	~ClassA()
	{
		if (a != NULL)
		{
			a = NULL;
			delete [] a;
		}
		cout << "delete";
	}
};

void main()
{
	ClassA a;
	a.abc();
	cout << "123";
}

Kết quả xuất ra là:

delete123delete

Trong lý thuyết nói hàm destructor chỉ chạy 1 lần cho mỗi đối tượng khi không dùng nữa. Nhưng theo code này thì hàm destructor được gọi 2 lần. 1 lần là sau lệnh return *this, và 1 lần là trước khi kết thúc chương trình. Mình muốn hiểu rõ hơn về về vấn đề này.
Mong được giải đáp.

Gió viết 20:31 ngày 30/09/2018
  1. Destructor bị lỗi: delete []a trước khi gán = NULL
  2. Vấn đề self assignment. a=a thì 2 object cùng giữ 1 con trỏ nên destructor sẽ bị lỗi
  3. Bạn đã tạo ra 1 obj mới từ hàm .abc() nên dù gán =biến hay không thì nó vần bị huỷ = destructor
Mai Anh Dũng viết 20:32 ngày 30/09/2018

Đó là bởi vì khi bạn return *this từ hàm abc tức là bạn tạo ra và trả về một thực thể(instance) của class đó. Và bởi vì bạn không gán giá trị trả về này cho biến nào nên nó bị hủy ngay luôn tại thời điểm đấy.

Đây là code chứng minh ( Sửa lại code của bạn, bỏ đi cái không cần thiết )

#include <iostream>

class ClassA {
public:
    ClassA() {
        std::cout << "constructor - address: " << this << std::endl;
    }

    ClassA abc() {
        std::cout << "inside abc - address: " << this << std::endl;
        return *this;
    }

    ~ClassA() {
        std::cout << "destructor of " << this << std::endl;
    }
};

int main() {
    ClassA a;
    a.abc();
    std::cout << "end of main\n";
}

Kết quả:

constructor - address: 0x28fefe
inside abc - address: 0x28fefe
destructor of 0x28feff
end of main
destructor of 0x28fefe

Trong đó địa chỉ của Object cha là 0x28fefe, địa chỉ của object được tạo ra từ hàm abc0x28feff

Ta thấy object con bị hủy ngay lập tức

destructor of 0x28feff

Còn object cha bị hủy khi kết thúc hàm main

destructor of 0x28fefe
Hồ Dương Nhật Duy viết 20:24 ngày 30/09/2018

Cảm ơn, em hiểu rồi.
Em có thử sửa lại hàm abc như sau:

ClassA* abc() {
std::cout << "inside abc - address: " << this << std::endl;
return this;
}

như vậy thì khi return có phải sẽ không tạo ra obj mới nên sẽ không bị destructor. Và đây có phải cách tốt nhất không? Nếu không thì anh có thể cho em xin 1 vài gợi ý. Em cảm ơn.

Đoàn Hiếu Tâm viết 20:30 ngày 30/09/2018

Cái này khi gọi trong hàm main sẽ lấy con trỏ của biến a, nên cẩn thân khi gán sẽ gặp vấn đề self assignment

Mai Anh Dũng viết 20:33 ngày 30/09/2018

như vậy thì khi return có phải sẽ không tạo ra obj mới nên sẽ không bị destructor.

Vì bây giờ nó trả về con trỏ, trỏ tới thực thể ban đầu

Và đây có phải cách tốt nhất không?

Tùy vào nhu cầu sử dụng, nếu em muốn sử dụng một thực thể thì nên return con trỏ thôi. Thì đây là cách tốt nhất.

Hồ Dương Nhật Duy viết 20:33 ngày 30/09/2018

Em hiểu rồi. Cảm ơn mọi người nhiều.

Bài liên quan
0