我意识到使用initializer_list复制构造函数而不是移动构造函数来初始化向量。例如下面的代码打印copy
class A {
public:
A(const string& ss): s(ss) {}
A(A&& other) {
cout << "move" << endl;
s = std::move(other.s);
}
A(const A& other) {
cout << "copy" << endl;
s = other.s;
}
A& operator=(const A& other) {
cout << "copy =" << endl;
s = other.s;
return *this;
}
A& operator=(A&& other) {
cout << "move =" << endl;
s = std::move(other.s);
return *this;
}
private:
string s;
};
int main() {
vector<A> as = vector{
A("abc"),
};
}
Run Code Online (Sandbox Code Playgroud)
这需要模板类型具有复制构造函数。有没有办法实现相同但仅使用移动构造函数?我知道push_back通过rvalue调用移动构造函数(例如下面的代码)。但是如果向量用多个元素初始化,它可能会很长。
int main() {
vector<A> as;
as.push_back(A("abc"));
}
// output "move"
Run Code Online (Sandbox Code Playgroud)
std::initializer_list使副本所赋予它的价值。那些副本是const,所以如果它想移动它们vector甚至不能移动它们。因此,vector使用花括号初始化器列表初始化/分配 a将始终执行复制操作,而不是移动操作。
即使您将代码更改为使用A[]数组作为输入,将数组的迭代器传递给vector构造函数,vector仍然会从数组中复制值,而不是移动它们。
但是,您可以做的是使用std::vector::emplace():
int main() {
A ghi("ghi");
vector<A> as;
as.emplace(as.end(), "abc", A("def"), std::move(ghi), ...);
}
Run Code Online (Sandbox Code Playgroud)
更新:或者,如果您有很多值要放入vector,并且您不想像这样做那样对列表进行硬编码,那么您可以使用该std::move()算法(不要与std::move()类型转换混淆),例如:
int main() {
A items[] = {"abc", "def", "ghi", ...};
// or whatever sequence you want to store the values in,
// as long as it supports iterators...
vector<A> as;
as.reserve(std::size(items));
std::move(std::begin(items), std::end(items), std::back_inserter(as));
}
Run Code Online (Sandbox Code Playgroud)
这基本上只是一个std::vector::push_back()循环的包装器:
vector<A> as;
as.reserve(std::size(items));
for(auto &val : items) {
as.push_back(std::move(val));
}
Run Code Online (Sandbox Code Playgroud)
更新:或者,您可以在构造函数中使用移动迭代器vector:
vector<A> as(
std::make_move_iterator(std::begin(items)),
std::make_move_iterator(std::end(items))
);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
58 次 |
| 最近记录: |