Có nhiều cách sao chép std::vector, mỗi cách có đặc điểm hiệu năng và ngữ nghĩa khác nhau.
1. Copy Constructor (Khuyến nghị nhất)
vector<int> v1 = {1,2,3,4};
vector<int> v2(v1); // direct initialization
vector<int> v3 = v1; // copy initialization
// Deep copy, O(N), exception-safe
2. Assignment Operator
vector<int> v2; v2 = v1; // copy assignment, O(N), strong exception guarantee
3. assign() member function
vector<int> v2; v2.assign(v1.begin(), v1.end()); // iterator range v2.assign(5, 10); // 5 copies of 10
4. std::copy + back_inserter
#include <algorithm> #include <iterator> vector<int> v2; copy(v1.begin(), v1.end(), back_inserter(v2)); // Cần v2.reserve(v1.size()) trước để tránh reallocate nhiều lần
5. Range-based for + push_back
vector<int> v2; v2.reserve(v1.size()); for (int x : v1) v2.push_back(x);
6. Constructor range (C++11)
vector<int> v2(v1.begin(), v1.end()); // từ iterator pair
So sánh hiệu năng & ngữ nghĩa
| Phương pháp | Độ phức tạp | Exception safety | Ghi chú |
|---|---|---|---|
| Copy ctor / operator= | O(N) | Strong | Code ngắn, rõ nghĩa, tối ưu nhất (move nếu có) |
| assign(begin, end) | O(N) | Basic | Hữu ích khi v2 đã tồn tại, muốn clear rồi copy |
| std::copy + back_inserter | O(N) | Basic | Cần reserve thủ công, linh hoạt (có thể transform) |
| push_back loop | O(N) amortized | Basic | Chậm hơn do check size mỗi lần, trừ khi reserve |
| Constructor range | O(N) | Strong | Tương tự copy ctor nhưng từ iterator bất kỳ |
Shallow vs Deep Copy
- Vector chứa kiểu giá trị (
int,string,Point...) → Deep copy tự động (gọi copy ctor của phần tử). - Vector chứa con trỏ raw (
vector<T*>) → Shallow copy (copy địa chỉ). Cần tự quản lý sở hữu – khuyến nghị dùngunique_ptr/shared_ptr.
Move Semantics (C++11) – "Copy" không tốn O(N)
vector<int> v1 = {1,2,3};
vector<int> v2 = std::move(v1); // v2 "cướp" tài nguyên v1, v1 rỗng
// O(1) – chỉ copy 3 con trỏ (data, size, capacity)
Khuyến nghị
- Mặc định:
vector<T> v2 = v1;hoặcvector<T> v2(v1);. - Cần copy một phần:
vector<T> v2(v1.begin()+2, v1.end()-1);. - Cần transform khi copy:
transform(v1.begin(), v1.end(), back_inserter(v2), func);. - Không còn cần v1:
std::move(v1).