我有两个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
。
答案 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
的组合来完成。首先在上半年交换A
和B
。然后swap
空std::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)
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必须声明一个移动分配运算符。