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.

1 Like
  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
2 Likes

Đó 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
2 Likes

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.

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

1 Like

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

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.

1 Like

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

83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?