Cần giúp đỡ về Copy Constructor

#include <iostream>

using namespace std; 

class Jacger
{
public:
	int length(void);
	Jacger(int len);
	Jacger( const Jacger &box); 
	~Jacger();

private:
	int *ptr;
};

Jacger::Jacger( int len){
	ptr = new int;						
   *ptr = len;							
}	

Jacger::Jacger( const Jacger &box){		
	ptr = new int;						
       *ptr = *box.ptr;						
}

Jacger :: ~Jacger(){
	delete ptr;							
}

int Jacger::length(){
	return *ptr;
}

void function( Jacger ultra){
	cout << "Lrnght of values is : " << ultra.length << endl;
}

int main(){
	Jacger Jacger(10);
	function(Jacger);
}

Mk có 4 vấn đề chưa hiểu ở dòng code trên :
- Dòng 17: Nếu viết như trên thì mk đặt cấp phát động cho địa chỉ “*ptr” à ?
- Dòng 18: Hoặc mk nghĩ nếu đặt CPD cho địa chỉ thì giá trị cũng bị ảnh hưởng theo => … ?
- Dòng 23: Nếu đặt 1 cái như trên rồi sao phải đặt cái nữa ?
- Dòng 24: mk chưa hiểu dòng này -_-
// mk đã nghĩ hơn 1 ngày rồi vẫn chưa ra, mong mọi người giúp mk :stuck_out_tongue:

Dòng 17-19: Constructor bình thường:

  • Cấp phát động vùng bộ nhớ int, gán địa chỉ vào biến ptr (kiểu dữ liệu là int*);
  • Gán len vào vùng dữ liệu mà ptr trỏ đến.
    Dòng 22-24: Copy constructor:
  • Biến số box là tham chiếu đến object cần copy (kiểu dữ liệu const Jacger &);
  • Cấp phát động rồi gán ptr;
  • Lấy member ptr trong object box, lấy dữ liệu mà box.ptr trỏ đến ( toán tử *), gán vào vùng dữ liệu mà ptr (bên trái) trỏ đến, biểu thức bên phải có thể viết lại là: *(box.ptr).
    Dấu * và dấu &, mỗi cái đều có 2 tác dụng khác nhau tùy trường hợp, đừng nhầm nhé bạn.
    Lần sau bạn đừng viết tắt và ráng viết rõ ràng dùm nhé.
2 Likes

Oki bạn :)) mk sẽ cố gắng ko viết tắt nữa :stuck_out_tongue:

Chỗ copy constructor có thể viết đơn giản: ptr = new int(*(box.ptr)); như vậy dễ nhìn ra hơn. (int cũng có constructor vậy)

1 Like

Cho mình hỏi: cấp phát động chỉ có phạm vi trong scope “{ }” thôi à ?

Cấp phát động rồi thì bạn dùng ở đâu cũng được, miễn là bạn giữ được giá trị pointer để truy cập.
Giữ giá trị pointer để còn free vùng nhớ nữa.

Cái đấy thì ok rồi, nhưng ý mình muốn hỏi là mỗi lần dùng cấp phát động thì nó chỉ cấp trong phạm vi scope “{ }” thôi à ? Bởi vì trong vd trên mình thấy có 2 lần cấp phát động mà, 1 là ở Jacger :: Jacger() và 2 là ở Jacger::Jacger(const Jacger &box)

C++ không có tự động GC :slight_smile: nên ko lo bị xóa.

Mình mới vào group :), bạn có thể nói rõ hộ mk GC là gì đc ko ?

Garbage Collection. Trừ phi bạn xài smart pointer chứ C++ không có tự hủy cấp phát động.

Ukm, cảm ơn bạn, mà dù sao mk cũng có xài lệnh delete cấp phát động rồi nên ko lo :slight_smile:

Khi bạn viết thế này:

Jacger a(2); // => Jacger::Jacger(int len)

thì constructor Jacger::Jacger(int len) được chạy, và a có member ptr được gán giá trị con trỏ.
Còn khi bạn viết thế này:

Jacger a(2); // => Jacger::Jacger(int len)
Jacger b(a); // => Jacger::Jacger(const Jacger &box)

thì bước đầu là như ví dụ trên, sau đó Jacger::Jacger(const Jacger &box) được chạy, và theo code, thì vùng nhớ (do ptr trỏ) bên a được copy sang bên b (*ptr = *box.ptr).

Còn khi nào copy constructor được gọi, thì khá là phức tạp, thường là ở các phép gán, phép tạo dữ liệu như:

Jacger a(2); 
Jacger b(a); // copy từ a sang b
Jacger c = a; // copy từ a sang c
// Nếu có function kiểu này:
void abc(Jacger param);
// rồi gọi kiểu này
abc(b);
// thì b được copy vào param bằng copy constructor, nhưng compiler có thể optimize, vì vậy không nên đưa logic thiết yếu vào trong copy constructor.

Bạn có thể tham khảo https://en.wikipedia.org/wiki/Copy_constructor_(C%2B%2B)
Vậy thôi, chứ mình cũng chẳng hiểu là bạn muốn sao.

Chi tiết quá!! Cảm ơn bạn nhé, tuy ý tưởng ko gặp nhau nhưng bạn phần nào giúp mình hiểu hơn về copy constructor rồi :))

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