簡體   English   中英

STL向量:移動向量的所有元素

[英]STL vector: Moving all elements of a vector

我有兩個STL向量AB ,我想清除的所有元素A和移動的所有元素BA然后清除出B 簡單地說,我想這樣做:

std::vector<MyClass> A;
std::vector<MyClass> B;
....
A = B;
B.clear();

由於B可能很長,因此需要k*O(N)來執行此操作,其中k是常數,並且Nmax(size_of(A), size_of(B)) 我想知道是否有更有效的方法可以做到這一點。 我能想到的一件事是將AB定義為指針,然后在恆定時間內復制指針並清除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的組合來完成。 首先交換上半場的AB 然后用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM