30/09/2018, 18:17

Lại là operator=

Có vẻ mình vẫn chưa luyện tới đỉnh cái operator= này, mời mọi người xem thử và giải đáp giúp:

class Node {
public:
	int data;
	Node* next;
	Node() {
		data = 0;
		next = NULL;
	}

	Node(int data) {
		this->data = data;
		this->next = NULL;
	}
};

class CList {
private:
	int count;
	Node* pHead;
public:
	CList() {
		count = 0;
		pHead = NULL;
	}

	~CList() {
		count = 0;
		Node*pTemp = this->pHead;
		while (pHead) {
			pHead = pHead->next;
			delete pTemp;
			pTemp = pHead;
		}
	}

	CList(const CList& x) {
		Node* pTemp2 = x.pHead;
		while (pTemp2) {
			Node* pTemp1 = new Node();
			pTemp1->data = pTemp2->data;
			if (this->pHead == NULL) {
				this->pHead = pTemp1;
			}
			else {
				Node* pPos = this->pHead;
				while (pPos->next != NULL) {
					pPos = pPos->next;
				}
				pPos->next = pTemp1;
			}
			pTemp2 = pTemp2->next;
		}
		this->count = x.count;
	}
        //Gán LinkedList
	CList& operator=(const CList& x) {
		if (this->pHead) {
			Node*pTemp = this->pHead;
			while (this->pHead) {
				this->pHead = this->pHead->next;
				delete pTemp;
				pTemp = this->pHead;
			}
		}
		Node* pTemp2 = x.pHead;
		while (pTemp2) {
			Node* pTemp1 = new Node();
			pTemp1->data = pTemp2->data;
			if (this->pHead == NULL) {
				this->pHead = pTemp1;
			}
			else {
				Node* pPos = this->pHead;
				while (pPos->next != NULL) {
					pPos = pPos->next;
				}
				pPos->next = pTemp1;
			}
			pTemp2 = pTemp2->next;
		}
		this->count = x.count;
		return *this;
	}
        //Cộng 2 LinkedList
	CList operator+(const CList& x) { 
		CList re = *this;
		re.count += x.count;
		Node* pTemp = re.pHead;
		while (pTemp->next) {
			pTemp = pTemp->next;
		}
		pTemp->next = x.pHead;
		return re;
	}
};

Ở hàm main mình cho CList c = a + b thì nó báo lỗi valid heap pointer, mình nghĩ mình nó bị sai ở chỗ operator = và copy constructor (tuy nhiên mình test trường hợp cho CList c = a thì chạy ngon lành không văng lỗi gì cả)…

viết 20:24 ngày 30/09/2018

trong operator+
pTemp->next = x.pHead;
ko thể viết tắt như vậy được, phải copy từng phần tử trong x. Nếu viết tắt như vậy thì
c = a + b;
thì (a+b) sau khi được gán vào c sẽ được giải phóng, mà viết tắt như vậy thì nó giải phóng luôn b (a vẫn an toàn vì có re copy). Tới khi giải phóng b thì gặp lỗi đã giải phóng rồi, giải phóng lần nữa là sai.

huy vo viết 20:25 ngày 30/09/2018
CList operator+(const CList& x) {
		Node* pTemp2 = x.pHead;
		CList re = *this;
		re.count += x.count;
		Node* pTemp = re.pHead;
		while (pTemp->next) {
			pTemp = pTemp->next;
		}
		while (pTemp2) {
			pTemp->next = pTemp2;
			pTemp2 = pTemp2->next;
			pTemp = pTemp->next;
		}
		return re;
	}

Vẫn còn lỗi :’(

viết 20:22 ngày 30/09/2018

pTemp->next = pTemp2; gán kiểu vậy cũng là gán về phần tử nằm trong x. Phải new ra hẳn phần tử mới luôn

ko muốn new thì có thể xài copy của x chứ ko phải chính x (tham trị thay vì tham chiếu)

trong code ban đầu sửa có 1 dòng và thêm 1 dòng thôi =)

CList operator+(CList x) //thay vì xài const CList& x
{
    CList re = *this;
    re.count += x.count;
    Node* pTemp = re.pHead;
    while (pTemp->next) {
        pTemp = pTemp->next;
    }
    pTemp->next = x.pHead;
    x.pHead = NULL; //gán NULL x.pHead để khi kết thúc operator+, x ko xóa list mà phead trỏ tới lúc đầu nữa. List x ban đầu nay đã thuộc về re. Đây là list copy nên ko đụng với list b trong phép gán a + b
    return re;
}

cả operator= nữa, xài copy-and-swap luôn, truyền tham trị CList x, swap countpHead 6 dòng là xong rồi

huy vo viết 20:31 ngày 30/09/2018

Mình chưa hiểu lắm đoạn không delete this vì có re copy :v có phải là sau khi ra khỏi phương thức thì các đối tượng gồm this và tham số truyền vào đều sẽ bị delete?

viết 20:30 ngày 30/09/2018

vì khi viết
c = a + b;
thì toàn bộ vế phải của phép gán, hay a + b, là 1 object riêng biệt (object được trả về từ operator+). Khi gán object này cho c xong rồi thì nó sẽ được giải phóng. Nếu ko copy *this ra riêng thì mấy phần tử trong dslk mà this trỏ tới lại được thêm object (a+b) nắm quyền giải phóng nữa, thành ra cuối cùng nó sẽ bị giải phóng 2 lần. Dslk mà this trỏ tới ko bị giải phóng ngay sau operator+ mà được giải phóng khi nào phạm vị (scope) của nó kết thúc. Ở đây a + b thì this là con trỏ tới a, mà phạm vi của a là nằm trong thân hàm main, nên khi nào main kết thúc thì a mới được giải phóng.

mà nếu ko copy ra re riêng thì a cũng bị thay đổi rồi.
CList operator+(CList x)const
thêm chữ const sau phương thức này để bảo đảm this->pHead và this->n ko bị thay đổi. Nhưng dslk mà this trỏ tới vẫn thay đổi được thì phải?

huy vo viết 20:25 ngày 30/09/2018

Cám ơn nhé, hôm qua tới giờ ngộ ra được 1 mớ chân lí rồi…
Nhưng ở chỗ này:

CList operator+(CList x) //thay vì xài const CList& x
{
    CList re = *this;
    re.count += x.count;
    Node* pTemp = re.pHead;
    while (pTemp->next) {
        pTemp = pTemp->next;
    }
    pTemp->next = x.pHead;
    x.pHead = NULL; //gán NULL x.pHead để khi kết thúc operator+, x ko xóa list mà phead trỏ tới lúc đầu nữa. List x ban đầu nay đã thuộc về re. Đây là list copy nên ko đụng với list b trong phép gán a + b
    return re;
}

Nếu có constructor copy thì x lúc này là 1 list riêng không dính gì tới b, pHead của x khác với pHead của b thì đâu cần phải x.pHead = NULL đúng không nhỉ

À mà thôi, lên lớp làm bài tập thầy chỉ cho rồi :v

Bài liên quan
0