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

时间:2012-09-27 02:55:55

标签: c++ stl stdvector

我有两个STL向量AB,我想清除A的所有元素,并将B的所有元素移到A然后清除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

8 个答案:

答案 0 :(得分:67)

使用C ++ 11,它很简单:

A = std::move(B);

现在A包含以前由B持有的元素,而B现在为空。这样可以避免复制:内部表示只是从B移动到A,因此这是一个O(1)解决方案。

对于C ++ 03,正如Prætorian所说,你可以交换向量。 std::swap函数有一个特化,它以std::vector为参数。这有效地交换了内部表示,因此您最终避免创建它们所持有的元素的副本。此功能也适用于O(1)复杂度。

答案 1 :(得分:12)

如果你有一个C ++ 11编译器,你可以将B移到A

A = std::move(B);

如果您正在使用较旧的编译器,只需swap两个

A.swap(B);

在这两种情况下,唯一的 O(N)操作将清除A的内容。在第一种情况下,清除将在赋值本身期间完成,而在第二种情况下,它将在B超出范围时发生(因为内容被交换)。

答案 2 :(得分:3)

  

我有两个STL向量A和B,我想清除A的所有元素并将B的所有元素移动到A然后清除B。

这可以通过swap的组合来完成。首先在上半年交换AB。然后swapstd::vector<> B或致电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);

答案 3 :(得分:3)

只需在向量上调用clear就需要o(1)时间,因为clear将无所作为, 如果您真的想在将其分配给A后清除B,则可以执行以下操作

A.swap(B);
{
    std::Vector<..> C;
    c.swap(B);
}

答案 4 :(得分:2)

交换功能可以做到这一点。

#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:

答案 5 :(得分:1)

如果你不能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具有相同数量的元素,但它们都处于不确定状态(即,它们可以分配或销毁,但不能读取)。

答案 6 :(得分:1)

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

答案 7 :(得分:0)

我缺乏评论意见,但我想提到以下内容:https://en.cppreference.com/w/cpp/container/vector/operator%3D void.pointer是正确的。特别是...

  

2)移动分配运算符。使用移动语义将其他内容替换为其他内容(即,其他中的数据从其他中移入此容器)。另一个之后处于有效但未指定的状态。

因此,按照标准,Praetorian的回答是错误的。但是,至少对于MSVC来说已经足够了,因为该实现无论如何都会清除列表(对于大多数情况可能如此)。

有趣的是,由于我们声明了move构造函数,因此不会声明任何隐式的move赋值运算符。因此,我们“知道” std :: vector必须声明一个移动分配运算符。