61

我有两个 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))。我想知道是否有更有效的方法来做到这一点。我能想到的一件事是将Aand定义B为指针,然后在恒定时间内复制指针并清除B

4

8 回答 8

108

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

A = std::move(B);

现在A包含以前由 持有的元素,B现在B是空的。这避免了复制:内部表示只是简单地从 移动BA,所以这是一个O(1)解决方案。

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

于 2012-09-27T02:58:09.527 回答
16

如果你有 C++11 编译器,你可以B进入A.

A = std::move(B);

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

A.swap(B);

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

于 2012-09-27T02:59:21.787 回答
5

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

这可以通过组合来完成swap。第一次交换AB上半场。然后swap一个空std::vector<>的 withB或 call 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);
于 2012-09-27T03:13:29.297 回答
4

只需在向量上调用 clear 将花费 o(1) 时间,因为 clear 不会做任何事情,如果您真的想在将 B 分配给 A 后清除 B,您可以执行以下操作

A.swap(B);
{
    std::Vector<..> C;
    c.swap(B);
}
于 2012-09-27T03:17:41.737 回答
4

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
于 2018-05-17T11:46:32.183 回答
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:
于 2012-09-27T03:07:58.997 回答
2

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

于 2016-09-22T02:08:11.267 回答
2

我没有代表发表评论,但我想提一下:https: //en.cppreference.com/w/cpp/container/vector/operator%3D void.pointer 是正确的。尤其是...

2) 移动赋值运算符。使用移动语义将内容替换为 other 的内容(即 other 中的数据从 other 移动到此容器中)。other 之后处于有效但未指定的状态。

因此,根据标准,Praetorian 的答案是错误的。但是,至少对于 MSVC 来说,这已经足够好了,因为无论如何该实现都会清除列表(对于大多数人来说可能是正确的)。

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

于 2019-01-09T07:06:03.340 回答