[英]STL vector: Moving all elements of a vector
我有兩個STL向量A
和B
,我想清除的所有元素A
和移動的所有元素B
到A
然后清除出B
。 簡單地說,我想這樣做:
std::vector<MyClass> A;
std::vector<MyClass> B;
....
A = B;
B.clear();
由於B
可能很長,因此需要k*O(N)
來執行此操作,其中k
是常數,並且N
是max(size_of(A), size_of(B))
。 我想知道是否有更有效的方法可以做到這一點。 我能想到的一件事是將A
和B
定義為指針,然后在恆定時間內復制指針並清除B
使用C ++ 11,它很簡單:
A = std::move(B);
現在A
包含以前由B
持有的元素,而B
現在是空的。 這避免了復制:內部表示只是從B
移動到A
,因此這是一個O(1)
解決方案。
對於C ++ 03,正如Prætorian所說,你可以交換向量。 std::swap
函數有一個特化,它以std::vector
s作為參數。 這有效地交換了內部表示,因此您最終避免創建它們所持有的元素的副本。 此功能也適用於O(1)
復雜度。
如果你有一個C ++ 11編譯器,你可以將B
移動到A
A = std::move(B);
如果您正在使用較舊的編譯器,只需swap
這兩個
A.swap(B);
在這兩種情況下,唯一的O(N)操作將清除A
的內容。 在第一種情況下,清除將在賦值本身期間完成,而在第二種情況下,它將在B
超出范圍時發生(因為內容被交換)。
我有兩個STL向量A和B,我想清除A的所有元素並將B的所有元素移動到A然后清除B.
這可以通過swap
的組合來完成。 首先交換上半場的A
和B
然后用B
swap
空的std::vector<>
或調用clear()
。 區別在於clear()
不會釋放內存,只會破壞對象:
std::vector<int> a, b; // initialize them somehow
swap(a,b);
// clear b without releasing the memory:
std::size_t capacity = b.capacity();
b.clear();
assert(b.capacity()==capacity);
// or release the memory
std::vector<int>().swap(b);
assert(b.capacity()==0);
只需在向量上調用清除將花費o(1)時間,因為clear將無效,如果你真的想在將其分配給A之后清除B,你可以執行以下操作
A.swap(B);
{
std::Vector<..> C;
c.swap(B);
}
交換功能執行此操作。
#include <iostream>
#include <iterator>
#include <vector>
int main(int argc, char* argv)
{
std::vector<int> A;
std::vector<int> B;
for (int i = 0; i < 10; ++i)
{
B.push_back(i);
}
std::cout << "Before swap\n";
std::cout << "A:";
std::copy(A.begin(), A.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << "\nB:";
std::copy(B.begin(), B.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << "\n";
A.swap(B);
B.clear();
std::cout << "After swap\n";
std::cout << "A:";
std::copy(A.begin(), A.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << "\nB:";
std::copy(B.begin(), B.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << "\n";
}
輸出
Before swap
A:
B:0 1 2 3 4 5 6 7 8 9
After swap
A:0 1 2 3 4 5 6 7 8 9
B:
std :: move工作得很好。 這是相同的示例代碼
vector<int> v1 = {1,2,3,10,20,30,100,200,300,999};
vector<int> v2;
cout << "Size of v1 before move = " << v1.size() << endl;
cout << "Capacity of v1 before move = " << v1.capacity() << endl;
v2 = std::move(v1);
cout << "Size of v2 after move = " << v2.size() << endl;
cout << "Capacity of v2 after move = " << v2.capacity() << endl;
cout << "Size of v1 after move = " << v1.size() << endl;
cout << "Capacity of v1 after move = " << v1.capacity() << endl;
-----------Output-------------------------
Size of v1 before move = 10
Capacity of v1 before move = 10
Size of v2 after move = 10
Capacity of v2 after move = 10
Size of v1 after move = 0
Capacity of v1 after move = 0
如果你不能std :: move或std :: swap這些向量(例如,因為A和B是相關但不同的類型,可能只有const不同),你可以這樣做:
std::vector<MyClass> A;
std::vector<const MyClass> B;
// ...
for( auto& a : A )
{
B.emplace_back( std::move( a ) );
}
請注意,這會使A具有相同數量的元素,但它們都處於不確定狀態(即,它們可以分配或銷毀,但不能讀取)。
我沒有回復評論,但我想提一下: https: //en.cppreference.com/w/cpp/container/vector/operator%3D void.pointer是對的。 特別是...
2)移動賦值運算符。 使用移動語義替換其他內容(即其他數據從其他數據移動到此容器中)。 其他人之后處於有效但未指明的狀態。
因此,Praetorian的答案每個標准都是錯誤的。 但是,對於MSVC至少,這已經足夠好了,因為無論如何實現都會清除列表(大多數情況下都是如此)。
有趣的是,由於我們聲明了一個移動構造函數,因此不會聲明隱式移動賦值運算符。 因此,我們“知道”std :: vector必須聲明一個移動賦值運算符。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.