如何正确使用std::move将参数移入C++类构造函数?
如何用最少拷贝将std::vector传入类中
先看基础场景代码:
class MyClass { public: MyClass(std::vector<int> v) : m_vector(v) {} void doSomething(); private: std::vector<int> m_vector; }; int main() { std::vector<int> myVector; // ... // 处理myVector // ... MyClass myItem(myVector); myItem.doSomething(); }
显然把vector移动到MyClass比拷贝高效,但不确定构造函数怎么写、参数怎么传。以下几个可编译版本里,哪个能保证最少拷贝?
版本A分析
MyClass(const std::vector<int>& v) : m_vector(std::move(v)) {} MyClass myItem(myVector);
v是const左值引用,std::move(v)得到的是const右值引用,而std::vector的移动构造函数只接受非const右值引用,所以这里实际会调用拷贝构造函数初始化m_vector- 总拷贝次数:1次
版本B分析
MyClass(std::vector<int> v) : m_vector(std::move(v)) {} MyClass myItem(myVector);
- 第一步:传递左值
myVector给形参v,调用拷贝构造函数创建v - 第二步:
std::move(v)将v移动到m_vector,调用移动构造(无拷贝) - 总拷贝次数:1次
版本C分析
MyClass(const std::vector<int>& v) : m_vector(v) {} MyClass myItem(std::move(myVector));
- 形参
v绑定到std::move(myVector)的右值,但因为是const引用,初始化m_vector时直接拷贝v的内容 - 总拷贝次数:1次
版本D分析
MyClass(const std::vector<int>& v) : m_vector(std::move(v)) {} MyClass myItem(std::move(myVector));
- 同样,
v是const引用,std::move(v)无法触发移动构造,m_vector还是通过拷贝构造初始化 - 总拷贝次数:1次
版本E分析
MyClass(std::vector<int>&& v) : m_vector(std::move(v)) {} MyClass myItem(std::move(myVector));
- 第一步:
std::move(myVector)把左值转为右值,匹配构造函数的右值引用形参v,这一步无拷贝(只是引用传递) - 第二步:
std::move(v)将v移动到m_vector,调用移动构造(无拷贝) - 总拷贝次数:0次,是所有版本里效率最高的
最优实践
如果要同时支持**传入左值(必须拷贝)和传入右值(可以移动)**的场景,推荐提供两个构造函数:
// 处理左值,执行拷贝 MyClass(const std::vector<int>& v) : m_vector(v) {} // 处理右值,执行移动 MyClass(std::vector<int>&& v) : m_vector(std::move(v)) {}
或者用C++11及以上的万能引用+完美转发,更简洁地覆盖所有情况:
template<typename T> MyClass(T&& v) : m_vector(std::forward<T>(v)) {}
这样不管传入左值还是右值,都会自动选择最优的构造方式,彻底避免不必要的拷贝。
内容的提问来源于stack exchange,提问作者Michele Spagnolo
相关产品推荐
相关产品推荐

