已用右值引用作参数时是否需调用std::move?如何实现通用构造函数?
C++构造函数相关问题解答
代码示例
class EntityBase { public: EntityBase() { std::cout << "EntityBase constructor called." << std::endl; } EntityBase(const std::string& name) : m_name(name) { std::cout << "EntityBase constructor string called." << std::endl; } EntityBase(std::string&& name) : m_name(std::move(name)) { std::cout << "EntityBase constructor string&& called." << std::endl; } ~EntityBase() { std::cout << "EntityBase destructor called." << std::endl; } private: std::string m_name; };
问题1:右值引用参数的构造函数里需要调用std::move(name)吗?
需要。核心原因是:所有有名字的变量都是左值,哪怕它的类型是右值引用。你这里的name虽然是右值引用类型,但它本身是一个左值表达式,直接赋值给m_name会触发std::string的拷贝构造函数,而非移动构造。只有通过std::move(name)把它转换成右值,才能触发移动构造,实现资源的高效转移,避免不必要的内存拷贝。
问题2:如何编写单一构造函数,同时支持左值和右值并自动执行复制/移动?
有两种常用实现方式:
方式一:万能引用+完美转发
利用模板实现万能引用,配合std::forward保持参数的左值/右值属性:
class EntityBase { public: EntityBase() { std::cout << "EntityBase constructor called." << std::endl; } template<typename T> EntityBase(T&& name) : m_name(std::forward<T>(name)) { std::cout << "EntityBase forwarding constructor called." << std::endl; } ~EntityBase() { std::cout << "EntityBase destructor called." << std::endl; } private: std::string m_name; };
这里的T&&是万能引用,会根据传入参数自动推导类型:传入左值时推导为左值引用,传入右值时推导为右值引用。std::forward<T>(name)则会完美转发参数的原始属性,让m_name自动调用对应类型的构造函数(拷贝或移动)。
方式二:值传递+移动赋值
这种写法更简洁,适合大多数场景:
class EntityBase { public: EntityBase() { std::cout << "EntityBase constructor called." << std::endl; } EntityBase(std::string name) : m_name(std::move(name)) { std::cout << "EntityBase value constructor called." << std::endl; } ~EntityBase() { std::cout << "EntityBase destructor called." << std::endl; } private: std::string m_name; };
传入左值时,会先拷贝构造函数参数name,再移动给m_name;传入右值时,会直接移动构造name,再移动给m_name。虽然多了一次移动操作,但std::string的移动代价极低,整体效率依然很高。
内容的提问来源于stack exchange,提问作者Tejas Anand
相关产品推荐
相关产品推荐

