对向量使用 std::move
Using std::move with vectors
我有一个关于在 C++ 中使用 std::move
的问题。
假设我有以下 class,它在其构造函数中将 std::vector
作为参数:
class A
{
public:
A(std::vector<char> v): v(v) {}
private:
std::vector<char> v;
};
但是如果我在某处写下以下内容:
std::vector<char> v;
A a(v);
std::vector
的拷贝构造函数会被调用两次,对吧?
那么我应该像下面这样为 A
编写构造函数吗?
class A
{
public:
A(std::vector<char> v): v(std::move(v)) {}
private:
std::vector<char> v;
};
如果我想调用以下内容怎么办?
std::vector<char> v;
A a(std::move(v));
构造函数的第二个版本可以吗,还是我应该为 A
创建另一个构造函数,它需要 std::vector<char>&&
?
你应该写一个移动构造函数!
A::A( std::vector<char>&& vec): v(std::move(vec) {}
如果你没有写那个,你会在这里再得到一份。
您必须记住,您的矢量将被移动 "away"。所以如果你这样写:
std::vector<char> v;
A a(std::move(v));
因此在调用 A 的构造函数后不应使用向量 v。所有元素都被移走,内容的迭代器无效。该向量可用于存储新数据。
所以如果你写
std::vector<char> v;
A a(v);
这将导致像您示例中那样的移动,没有人会期望移动。
创建两个构造函数:
第一个构造函数应该是 const&,第二个是 rvalue&& 所以它可以使用移动语义:
class A
{
public:
A(const std::vector<char>& v_) : v(v_) { std::cout << "const& ctor\n"; }
A(std::vector<char>&& v_) : v(std::move(v_)) { std::cout << "rvalue&& ctor\n"; }
private:
std::vector<char> v;
};
测试:
int main()
{
std::vector<char> v1{ 'a', 'b', 'c', 'd' };
A a1(v1);
A a2(std::vector<char>{ 1, 2, 3, 4 });
return 0;
}
输出:
const& ctor
rvalue&& ctor
很多时候,通过按值接受 vector
并从中移动,您会很好地使用向量。所以,
A(std::vector<char> v): v(std::move(v)) {}
但是,这假定您只是为 'natural' 左值或临时值调用它。意思是,它在
这样的情况下表现出色
A a(std::vector<char>{....}); // <--- 1
std::vector<char> my_vec;
A b(my_vec); // <--- 2
如果你希望用一个你想从中移动的左值来调用它,就像在你的例子中一样,那么你需要两个构造函数 - 带有 const lvalue
引用和 rvalue
引用:
A(const std::vector<char>& v) : v(v) { }
A(std::vector<char>&& v) : v(std::move(v)) { }
你的第二种方案没问题
第二个版本只会移动向量两次(将按值参数移动到您的成员中)。如果您不介意额外移动的成本,您可以坚持只将按值参数移动到您的成员中。
如果你介意,那就为参数的不同值类别制作两个构造函数。
我有一个关于在 C++ 中使用 std::move
的问题。
假设我有以下 class,它在其构造函数中将 std::vector
作为参数:
class A
{
public:
A(std::vector<char> v): v(v) {}
private:
std::vector<char> v;
};
但是如果我在某处写下以下内容:
std::vector<char> v;
A a(v);
std::vector
的拷贝构造函数会被调用两次,对吧?
那么我应该像下面这样为 A
编写构造函数吗?
class A
{
public:
A(std::vector<char> v): v(std::move(v)) {}
private:
std::vector<char> v;
};
如果我想调用以下内容怎么办?
std::vector<char> v;
A a(std::move(v));
构造函数的第二个版本可以吗,还是我应该为 A
创建另一个构造函数,它需要 std::vector<char>&&
?
你应该写一个移动构造函数!
A::A( std::vector<char>&& vec): v(std::move(vec) {}
如果你没有写那个,你会在这里再得到一份。
您必须记住,您的矢量将被移动 "away"。所以如果你这样写:
std::vector<char> v;
A a(std::move(v));
因此在调用 A 的构造函数后不应使用向量 v。所有元素都被移走,内容的迭代器无效。该向量可用于存储新数据。
所以如果你写
std::vector<char> v;
A a(v);
这将导致像您示例中那样的移动,没有人会期望移动。
创建两个构造函数: 第一个构造函数应该是 const&,第二个是 rvalue&& 所以它可以使用移动语义:
class A
{
public:
A(const std::vector<char>& v_) : v(v_) { std::cout << "const& ctor\n"; }
A(std::vector<char>&& v_) : v(std::move(v_)) { std::cout << "rvalue&& ctor\n"; }
private:
std::vector<char> v;
};
测试:
int main()
{
std::vector<char> v1{ 'a', 'b', 'c', 'd' };
A a1(v1);
A a2(std::vector<char>{ 1, 2, 3, 4 });
return 0;
}
输出:
const& ctor
rvalue&& ctor
很多时候,通过按值接受 vector
并从中移动,您会很好地使用向量。所以,
A(std::vector<char> v): v(std::move(v)) {}
但是,这假定您只是为 'natural' 左值或临时值调用它。意思是,它在
这样的情况下表现出色A a(std::vector<char>{....}); // <--- 1
std::vector<char> my_vec;
A b(my_vec); // <--- 2
如果你希望用一个你想从中移动的左值来调用它,就像在你的例子中一样,那么你需要两个构造函数 - 带有 const lvalue
引用和 rvalue
引用:
A(const std::vector<char>& v) : v(v) { }
A(std::vector<char>&& v) : v(std::move(v)) { }
你的第二种方案没问题
第二个版本只会移动向量两次(将按值参数移动到您的成员中)。如果您不介意额外移动的成本,您可以坚持只将按值参数移动到您的成员中。
如果你介意,那就为参数的不同值类别制作两个构造函数。