[英]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.