简体   繁体   English

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

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

I have two STL vectors A and B and I'd like to clear all elements of A and move all elements of B to A and then clear out B . 我有两个STL向量AB ,我想清除的所有元素A和移动的所有元素BA然后清除出B Simply put, I want to do this: 简单地说,我想这样做:

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

Since B could be pretty long, it takes k*O(N) to do this operation, where k is a constant, and N is max(size_of(A), size_of(B)) . 由于B可能很长,因此需要k*O(N)来执行此操作,其中k是常数,并且Nmax(size_of(A), size_of(B)) I was wondering if there could be a more efficient way to do so. 我想知道是否有更有效的方法可以做到这一点。 One thing that I could think of is to define A and B as pointers and then copy pointers in constant time and clear out B . 我能想到的一件事是将AB定义为指针,然后在恒定时间内复制指针并清除B

Using C++11, it's as simple as: 使用C ++ 11,它很简单:

A = std::move(B);

Now A contains the elements that were previously held by B , and B is now empty. 现在A包含以前由B持有的元素,而B现在是空的。 This avoids copying: the internal representation is simply moved from B to A , so this is an O(1) solution. 这避免了复制:内部表示只是从B移动到A ,因此这是一个O(1)解决方案。

As for C++03, as Prætorian states, you could swap the vectors. 对于C ++ 03,正如Prætorian所说,你可以交换向量。 There is a specialization of the std::swap function, which takes std::vector s as its arguments. std::swap函数有一个特化,它以std::vector s作为参数。 This effectively swaps the internal representation, so you end up avoiding creating copies of the elements held by them. 这有效地交换了内部表示,因此您最终避免创建它们所持有的元素的副本。 This function works in O(1) complexity as well. 此功能也适用于O(1)复杂度。

If you have a C++11 compiler you can move B into A . 如果你有一个C ++ 11编译器,你可以将B移动到A

A = std::move(B);

If you're working with an older compiler, just swap the two 如果您正在使用较旧的编译器,只需swap这两个

A.swap(B);

In both cases, the only O(N) operation will be clearing the contents of A . 在这两种情况下,唯一的O(N)操作将清除A的内容。 In the first case the clearing will be done during the assignment itself, while in the second it will happen when B goes out of scope (since the contents were swapped). 在第一种情况下,清除将在赋值本身期间完成,而在第二种情况下,它将在B超出范围时发生(因为内容被交换)。

I have two STL vectors A and B and I'd like to clear all elements of A and move all elements of B to A and then clear out B. 我有两个STL向量A和B,我想清除A的所有元素并将B的所有元素移动到A然后清除B.

This can be done with a combination of swap . 这可以通过swap的组合来完成。 First swap A and B for the first half. 首先交换上半场的AB Then swap an empty std::vector<> with B or call clear() . 然后用B swap空的std::vector<>或调用clear() The difference is that clear() will not release the memory, but only destroy the objects: 区别在于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);

just call clear on vector will take o(1) time, since clear will do nothing, If you really want to clear B after assign it to A, you could do the following 只需在向量上调用清除将花费o(1)时间,因为clear将无效,如果你真的想在将其分配给A之后清除B,你可以执行以下操作

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

The swap function does this. 交换功能执行此操作。

#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";
}

The output 输出

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 works fine. std :: move工作得很好。 Here is the sample code for the same 这是相同的示例代码

    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

If you can't std::move or std::swap the vectors (eg, because A and B are related but different types, perhaps differing only by const), you can do: 如果你不能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 ) );
}

Note that this leaves A with the same number of elements, but they are all in an indeterminate state (ie, they can be assigned to or destructed, but not read). 请注意,这会使A具有相同数量的元素,但它们都处于不确定状态(即,它们可以分配或销毁,但不能读取)。

I lack rep to comment, but I want to mention that per: https://en.cppreference.com/w/cpp/container/vector/operator%3D void.pointer is right. 我没有回复评论,但我想提一下: https: //en.cppreference.com/w/cpp/container/vector/operator%3D void.pointer是对的。 In particular... 特别是...

2) Move assignment operator. 2)移动赋值运算符。 Replaces the contents with those of other using move semantics (ie the data in other is moved from other into this container). 使用移动语义替换其他内容(即其他数据从其他数据移动到此容器中)。 other is in a valid but unspecified state afterwards. 其他人之后处于有效但未指明的状态。

Thus Praetorian's answer is wrong per standard. 因此,Praetorian的答案每个标准都是错误的。 However, for MSVC at least, is good enough because the implementation clears the list anyway (Probably true for most). 但是,对于MSVC至少,这已经足够好了,因为无论如何实现都会清除列表(大多数情况下都是如此)。

Something interesting is that since we declare a move constructor, no implicit move assignment operator will be declared. 有趣的是,由于我们声明了一个移动构造函数,因此不会声明隐式移动赋值运算符。 Thus we "know" that std::vector must declare a move assignment operator. 因此,我们“知道”std :: vector必须声明一个移动赋值运算符。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM