HOWTO · C++
在 C++ 中複製向量容器物件
本文演示瞭如何在 C++ 中複製向量容器物件。
本頁內容
複製 C++ 的 std::vector 時,建立新向量可使用複製建構函式;要替換既有向量的內容,則使用複製指定。若只複製一段範圍,可使用範圍建構函式。目的範圍已有足夠空間時可使用 std::copy;std::back_inserter 則會將元素附加到目的向量。這些操作會依照元素型別複製元素,不會透過指標遞迴複製所指向的物件。
使用複製建構函式或指定運算子複製向量
複製初始化會根據現有向量建立新向量:std::vector<int> copy = source;。直接初始化使用括號,效果相同:std::vector<int> copy(source);。若目的向量已存在,請使用指定:destination = source;。指定會取代目的向量中的元素。這些寫法都需要包含 <vector>。
執行以下範例:
本節中的程式碼以及顯示的標籤或輸出仍為英文。
#include <cstddef>
#include <iostream>
#include <vector>
int main() {
const std::vector<int> source{2, 4, 6};
std::vector<int> copy = source;
std::vector<int> destination{9};
destination = source;
for (std::size_t i = 0; i < copy.size(); ++i) {
if (i != 0) {
std::cout << ' ';
}
std::cout << copy[i];
}
std::cout << '\n';
for (std::size_t i = 0; i < destination.size(); ++i) {
if (i != 0) {
std::cout << ' ';
}
std::cout << destination[i];
}
std::cout << '\n';
}
2 4 6
2 4 6
此程式會將每個複製後的向量各自輸出在一行。std::vector<int> 的元素是值,因此修改其中一個向量的整數,不會改變另一個向量中對應的整數。
使用向量的範圍建構函式複製範圍
範圍建構函式接受半開的迭代器範圍:包含第一個迭代器所指的位置,但不包含第二個。使用括號可將此建構函式與初始化列表語法區分開來。
std::vector<int> copy(source.begin(), source.end()); 會複製整個範圍。若要複製子範圍,且這些迭代器涵蓋所需元素,可使用 std::vector<int> middle(source.begin() + 1, source.end() - 1);。
第一個宣告會複製所有元素;第二個則會複製此範例中的中間範圍。兩個迭代器都必須指向來源向量中的有效範圍。需要建立新目的向量時,無論要複製整個向量或其中一段,這都是方便的選擇。
使用 std::copy 複製範圍
std::copy 會寫入既有的目的範圍。請包含 <algorithm>,並在複製前確認目的範圍的元素數量至少與來源範圍相同。此演算法本身不會擴大向量。
先使用 std::vector<int> destination(source.size());,再呼叫 std::copy(source.begin(), source.end(), destination.begin());,即可提供足以容納來源元素的目的範圍。
若要複製子範圍,請傳入該範圍的起始與結束迭代器,並確保目的向量有足夠的元素。來源範圍與目的範圍不得以違反此演算法要求的方式重疊。
使用 std::back_inserter 附加複製的元素
若要附加元素並讓向量視需要自動增長,請包含 <algorithm> 和 <iterator>,並使用 std::back_inserter:
例如,先建立 std::vector<int> destination{10};,再呼叫 std::copy(source.begin(), source.end(), std::back_inserter(destination));,即可附加來源元素。
原有的 10 會保留在最前面,後面接著來源中的值。目的向量已有元素,或事先不打算設定最終大小時,這種寫法很實用。
使用迴圈與 push_back 複製元素
使用迴圈可以明確呈現逐一處理元素的操作。push_back 會將每個複製的值加到末尾,因此也會延長既有的目的向量。
宣告 std::vector<int> destination; 後,可用以下迴圈逐一複製:for (const int& value : source) { destination.push_back(value); }。
一般的複製工作通常使用向量複製建構函式或範圍建構函式會更清楚。若加入元素時還需要轉換或篩選每個元素,則適合使用迴圈。與標準向量操作一樣,迴圈會依照元素型別複製每個元素。
使用 assign 與 insert 替換或插入目的向量的元素
若要以某個範圍取代目的向量的內容,請使用 assign(first, last)。若要將來源範圍插入指定位置,同時保留目的向量的其他元素,請使用 insert(position, first, last)。
使用 destination.assign(source.begin(), source.end()); 可取代目的向量的內容。使用 destination.insert(destination.begin(), source.begin(), source.end()); 則可將來源範圍插入開頭。
插入位置必須是目的向量中的有效迭代器。若插入導致向量重新配置儲存空間,指向其元素的所有迭代器、指標與參考都會失效。若沒有重新配置,插入位置及其之後的迭代器與參考仍會失效;插入位置之前的則保持有效。插入後,請重新取得受影響的迭代器與參考。
了解複製向量時會複製哪些內容
std::vector 會連續儲存元素,並自行管理這些元素所使用的儲存空間。複製向量會建立另一個獨立的向量,並在其中放入原元素的副本。對於 std::vector<int>,複製的是整數值,因此之後修改其中一個向量的元素,不會改變另一個向量中的值。
其他元素型別的行為取決於該型別本身的複製操作。例如,複製由原始指標組成的向量時,複製的是指標值,不會建立新的指標所指物件。若元素是智慧指標,複製行為則依循其自身語義,例如 std::shared_ptr 會共享所有權。因此,向量本身彼此獨立,不代表其中元素所指向或管理的物件也彼此獨立。
選擇向量的複製方法
要建立新向量,請選擇複製建構或範圍建構函式。要取代既有目的向量的內容,請選擇複製指定或 assign。要在指定位置加入一段範圍,請使用 insert;若要讓目的向量增長並附加元素,請搭配 std::back_inserter 使用 std::copy。若要寫入已配置好元素的目的範圍,請使用搭配適當大小目的向量的 std::copy。若複製時還需對每個元素執行自訂處理,則可使用搭配 push_back 的迴圈。
若要完整複製並建立新向量,優先使用複製建構函式;若只需複製選定元素,則使用範圍建構函式。對既有向量,可選擇指定或 assign 取代內容、使用 insert 在指定位置加入元素,或使用 std::back_inserter 附加元素。