Copy Constructor là constructor đặc biệt tạo đối tượng mới bằng cách sao chép từ đối tượng cùng lớp đã tồn tại. Được gọi khi:
- Khởi tạo đối tượng từ đối tượng khác:
Class b = a; - Truyền đối tượng vào hàm theo giá trị:
func(obj) - Trả về đối tượng từ hàm theo giá trị:
return obj;
Cú pháp chuẩn
ClassName(const ClassName& other) {
// Sao chép dữ liệu từ other
}
Khi nào CẦN tự viết Copy Constructor?
- Lớp có con trỏ quản lý bộ nhớ động
- Lớp có tài nguyên cần deep copy (file handle, socket, GPU resource...)
- Cần logic sao chép tùy chỉnh
Nếu không tự viết, compiler tạo default copy constructor (shallow copy - sao chép bit-by-bit).
Ví dụ: Deep Copy cho class có con trỏ
#include <iostream>
using namespace std;
class Line {
public:
int getLength() const { return *ptr; }
Line(int len) { // Constructor thường
cout << "Constructor thuong cap phat ptr" << endl;
ptr = new int;
*ptr = len;
}
Line(const Line& obj) { // Copy Constructor - DEEP COPY
cout << "Copy constructor cap phat ptr." << endl;
ptr = new int;
*ptr = *obj.ptr; // Sao chép GIÁ TRỊ, không sao chép con trỏ
}
~Line() { // Destructor
cout << "Giai phong bo nho!" << endl;
delete ptr;
}
private:
int* ptr;
};
void display(Line obj) { // Truyền theo giá trị -> gọi copy constructor
cout << "Do dai: " << obj.getLength() << endl;
}
int main() {
Line line(10);
display(line); // Tạo bản sao, gọi copy constructor
return 0;
}
Kết quả
Constructor thuong cap phat ptr Copy constructor cap phat ptr. Do dai: 10 Giai phong bo nho! Giai phong bo nho!
Ví dụ 2: Tạo đối tượng mới từ đối tượng hiện có
int main() {
Line line1(10);
Line line2 = line1; // Gọi copy constructor
display(line1);
display(line2);
return 0;
}
Kết quả
Constructor thuong cap phat ptr Copy constructor cap phat ptr. Copy constructor cap phat ptr. Do dai: 10 Giai phong bo nho! Copy constructor cap phat ptr. Do dai: 10 Giai phong bo nho! Giai phong bo nho! Giai phong bo nho!
Shallow Copy vs Deep Copy
| Loại | Hành vi | Vấn đề |
|---|---|---|
| Shallow (Default) | Copy giá trị con trỏ | Double free, dangling pointer |
| Deep (Tự viết) | Cấp phát mới, copy dữ liệu | An toàn, độc lập |
Rule of Three / Five / Zero
- Rule of Three (C++98): Nếu cần 1 trong 3: destructor, copy constructor, copy assignment → cần cả 3
- Rule of Five (C++11): + move constructor, move assignment
- Rule of Zero: Dùng RAII (
vector,unique_ptr,shared_ptr) → không cần viết gì
C++11: Move Constructor
Line(Line&& other) noexcept : ptr(other.ptr) {
other.ptr = nullptr; // Chuyển quyền sở hữu
}
Khuyến nghị hiện đại
Tránh quản lý bộ nhớ thủ công. Dùngstd::vector,std::string,std::unique_ptr→ Compiler tự tạo đúng copy/move constructor.