01/10/2018, 11:27

Giúp em về operator=

Em có xây dựng 1 class về đa thức bên dưới:

#include<iostream>
using namespace std;
class DT {
	private:
		int bac;
		float* ptr;
	public:
		DT();
		~DT();
		friend istream& operator>>(istream& is,DT& u);
		friend ostream& operator<<(ostream& os,DT& u);
		DT& operator=(DT& u);
		DT operator+(DT u);
};
DT::~DT() {
	delete[] ptr;
}
DT::DT() {
	bac=0;
	ptr=new float[bac+1];
	for(int i=0;i<bac+1;i++)
		ptr[i]=0;
	}
istream& operator>>(istream& is,DT& u) {
	cout<<"Da thuc bac: ";
	is>>u.bac;
	u.ptr=new float[u.bac+1];
	for(int i=0;i<u.bac+1;i++) {
		cout<<"Nhap he so thu "<<i<<": ";
		is>>u.ptr[i];
	}
	return is;
}
ostream& operator<<(ostream& os,DT& u) {
	for(int i=0;i<u.bac;i++) {
		if(u.ptr[i+1]>=0) os<<u.ptr[i]<<"*x^"<<i<<" + ";
		else os<<u.ptr[i]<<"*x^"<<i<<" - ";
	}
	os<<u.ptr[u.bac]<<"*x^"<<u.bac;
	return os;
}
DT& DT::operator=(DT &u) {
	bac=u.bac;
	ptr=new float[bac+1];
	for(int i=0;i<bac+1;i++) {
		ptr[i]=u.ptr[i];
	}
	return u;
}
DT DT::operator+(DT u) {
	DT temp;
	temp.bac=u.bac>bac?u.bac:bac;
	temp.ptr=new float[temp.bac+1];
	int min=u.bac<bac?u.bac:bac;
	for(int i=0;i<min+1;i++) {
		temp.ptr[i]=ptr[i]+u.ptr[i];
	}
	for(int i=min+1;i<temp.bac+1;i++) {
		if(min==bac) {
			temp.ptr[i]=u.ptr[i];
		}
		else temp.ptr[i]=ptr[i];
	}
	return temp;
}
int main() {
	DT u,u1,u2;
	cout<<"Nhap 2 da thuc: "<<endl;
	cin>>u1>>u2;
	cout<<"
Da thuc 1: 
"<<u1;
	cout<<"
Da thuc 2: 
"<<u2;
	u=u1+u2; //loi 
	cout<<"
Da thuc tong la: 
"<<u1+u2;
}

Nhưng khi đến hàm main em gán u=u1+u2 thì không gán được mong mọi người chỉ giúp.
Em có thử để hàm operator+ trả về tham chiếu thì chương trình chạy nhưng vì hàm operator+ khi đó tham chiếu đến biến rác nên chương trình bị xung đột vùng nhớ khi chạy và bị dừng khi đang chạy.

DT& DT::operator+(DT u) {
	DT temp;
....
	return temp;
}

Mọi người cho em hỏi tại sao để tham chiếu nó chạy được còn không thì chương trình báo lỗi luôn.

Có cách nào để hàm trả về tham chiếu 1 biến cục bộ không như ở trên em muốn hàm trả về tham chiếu đến biến temp.

rogp10 viết 13:41 ngày 01/10/2018

Chịu khó thôi. Tới C++11 mới có move assignment, move constructor

Black viết 13:35 ngày 01/10/2018

thế bây giờ em muốn tính giá trị của u1+u2 thì phải làm sao.

Black viết 13:33 ngày 01/10/2018

Ai chỉ giúp em với khó hiểu ghê.

rogp10 viết 13:36 ngày 01/10/2018

Đành phải trả value về chứ sao giờ trả về ref thì bị sút ra vì dangling ref rồi. Nếu ko muốn alloc thêm thì cài op+= rồi dùng friend function 3 tham số, vẫn giữ được OOP.

Black viết 13:41 ngày 01/10/2018

Em đã thử làm lại bằng cách cấp phát bộ nhớ:

DT& DT::operator+(DT u) {
	DT *temp;
	temp=new DT;
	temp->bac=u.bac>bac?u.bac:bac;
	temp->ptr=new float[temp->bac+1];
	int min=u.bac<bac?u.bac:bac;
	for(int i=0;i<min+1;i++) {
		temp->ptr[i]=ptr[i]+u.ptr[i];
	}
	for(int i=min+1;i<temp->bac+1;i++) {
		if(min==bac) {
			temp->ptr[i]=u.ptr[i];
		}
		else temp->ptr[i]=ptr[i];
	}
	return *temp;
}

và chương trình đã chạy nhưng em có một vài chỗ vẫn không hiểu mong anh chỉ giúp.
1: Tại sao trả về tham chiếu nó lại cho gán u=u1+u2 trong khi trả về tham trị thì lại không.
2.Tại sao khi em cấp phát bộ nhớ thì lại có thể dùng hàm trả về tham chiếu còn không cấp phát thì lại bị dangling ref.

rogp10 viết 13:34 ngày 01/10/2018

Em thấy khi làm như cách ở trên thì sau khi ra khỏi thân hàm con trỏ int *temp cũng bị giải phóng và chỉ còn lại vùng nhớ khi cấp phát cho nó nhưng em chỉ return *temp chứ có return cái vùng nhớ ấy đâu mà sao vẫn trả về tham chiếu được nhỉ nó có khác gì so với em return temp như cách làm ban đầu đâu.

Vì đơn giản là cấp phát qua raw pointer thì hàm sẽ không tự hủy.

stackoverflow.com
Brian

When is the destructor of the temporary called

c++, c++11
answered by Brian on 06:40PM - 31 Mar 15
Black viết 13:36 ngày 01/10/2018

ý anh là khi cấp phát trên heap thì return temp sẽ bị leak mem phải return *temp.
Anh trả lời giúp em câu 1 nữa.

rogp10 viết 13:40 ngày 01/10/2018

Mình xem lại rồi, nên trả về temp luôn, vì compiler có thể dùng tham số ẩn để giữ temp (gọi là RVO), return *temp; sẽ không hay bằng vì nó bị new ra.

Câu 1 thì nhiều khả năng bạn cài đặt sai op= vì mình viết như vậy có sao đâu.

Black viết 13:34 ngày 01/10/2018

Hàm trả về tham chiếu mà anh sao trả về con trỏ được.

rogp10 viết 13:31 ngày 01/10/2018

Đương nhiên bạn phải sửa kiểu trả về ở prototype chứ
p/s: op+ leak mem. Nên viết copy constructor luôn cho đủ bộ ba.

Phân tích: Vấn đề là khi viết “khơi khơi” thì hàm có trách nhiệm gọi destructor, trỏ vào bằng con trỏ hay ref rồi trả về đều là sai vì sau đó là mất luôn. Còn bạn new ra thì hàm không hủy nên trỏ hay ref gì cũng được (đừng trả về ref, leak mem trừ phi có moving assignment/constructor).

Black viết 13:41 ngày 01/10/2018

Sao em thử gán: u=u1+u2 mà vẫn không được vậy. Vẫn phải để DT& hoặc DT* thì mới gán được còn nếu trả về tham trị thì nó không cho gán.
Rõ ràng là đơn giản chỉ trả về giá trị của temp rồi gán temp cho u mà sao phải trả về DT& hoặc DT* vậy anh.
Kiểu như em viết hàm tính tổng của 2 số nguyên đâu cần phải trả về tham chiếu gì đâu mà vẫn gán được u=u1+u2;

Black viết 13:34 ngày 01/10/2018

Cho em hỏi ngu chút leak mem là sao vậy anh. Google nó toàn ra memory leak.

rogp10 viết 13:36 ngày 01/10/2018

Sao em thử gán: u=u1+u2 mà vẫn không được vậy. Vẫn phải để DT& hoặc DT* thì mới gán được còn nếu trả về tham trị thì nó không cho gán.
Rõ ràng là đơn giản chỉ trả về giá trị của temp rồi gán temp cho u mà sao phải trả về DT& hoặc DT* vậy anh.
Kiểu như em viết hàm tính tổng của 2 số nguyên đâu cần phải trả về tham chiếu gì đâu mà vẫn gán được u=u1+u2;

Bạn phải cài copy constructor rồi. Sau đó ở op= sửa lại thành tham trị là giải quyết được lỗi này. (gọi là copy-and-swap idiom)

Bởi vì tham chiếu không được gán bằng rvalue, mà hàm luôn trả về rvalue.

Black viết 13:30 ngày 01/10/2018
#include<iostream>
#include<windows.h>
using namespace std;
class DT {
	private:
		int bac;
		float* ptr;
	public:
		DT();
		~DT();
        //copy constructor
		DT(const DT& u);
		friend istream& operator>>(istream& is,DT& u);
		friend ostream& operator<<(ostream& os,DT& u);
		DT& operator=(DT& u);
		DT operator+(DT u);
};
DT::~DT() {
	delete[] ptr;
}
DT::DT() {
	bac=1;
	ptr=new float[bac+1];
	for(int i=0;i<bac+1;i++)
		ptr[i]=0;
	}
DT::DT(const DT& u) {
	bac=u.bac;
	ptr=new float[u.bac+1];
	for(int i=0;i<u.bac+1;i++) {
		ptr[i]=u.ptr[i];
	}
}
istream& operator>>(istream& is,DT& u) {
	cout<<"Da thuc bac: ";
	is>>u.bac;
	u.ptr=new float[u.bac+1];
	for(int i=0;i<u.bac+1;i++) {
		cout<<"Nhap he so thu "<<i<<": ";
		is>>u.ptr[i];
	}
	return is;
}
ostream& operator<<(ostream& os,DT& u) {
	for(int i=0;i<u.bac;i++) {
		if(u.ptr[i+1]>=0) os<<u.ptr[i]<<"*x^"<<i<<" + ";
		else os<<u.ptr[i]<<"*x^"<<i;
	}
	os<<u.ptr[u.bac]<<"*x^"<<u.bac;
	return os;
}
DT& DT::operator=(DT &u) {
	bac=u.bac;
	ptr=new float[bac+1];
	for(int i=0;i<bac+1;i++) {
		ptr[i]=u.ptr[i];
	}
	return u;
}
DT DT::operator+(DT u) {
	DT temp;
	temp.bac=u.bac>bac?u.bac:bac;
	temp.ptr=new float[temp.bac+1];
	int min=u.bac<bac?u.bac:bac;
	for(int i=0;i<min+1;i++) {
		temp.ptr[i]=ptr[i]+u.ptr[i];
	}
	for(int i=min+1;i<temp.bac+1;i++) {
		if(min==bac) {
			temp.ptr[i]=u.ptr[i];
		}
		else temp.ptr[i]=ptr[i];
	}
	return temp;
}
int main() {
	DT u1,u2;
	cout<<"Nhap 2 da thuc: "<<endl;
	cin>>u1>>u2;
	cout<<"\nDa thuc 1: \n"<<u1;
	cout<<"\nDa thuc 2: \n"<<u2;
	DT u(u1+u2);
	cout<<"\nDa thuc tong la: \n"<<u;
}

Em viết hàm copy constructor rồi anh nó chạy được không cần phải trả về DT& hay DT* gì cả nhưng sao lại còn phải sửa cả operator= là sao anh.

Bài liên quan
0