C++构造函数中std::string初始化成员默认是拷贝还是移动?
回答
直接结论
- 当前你写的
m_member{p_member}初始化逻辑,默认执行std::string的拷贝构造,不会自动触发移动语义。 - 如果你要触发移动语义减少不必要的拷贝开销,必须显式添加
std::move(p_member)做类型转换。
原理说明
- 你的构造函数采用值传递接收
std::string参数:当调用方传入右值(比如示例里用字符串字面量"Test"构造的临时std::string)时,形参p_member本身会通过移动构造生成;如果调用方传入左值,形参p_member本身会通过拷贝构造生成。 - 但无论
p_member本身是怎么构造出来的,在初始化列表/函数体内,有名字的形参p_member属于左值——C++里所有带名字的变量,不管是局部变量还是函数形参,都是左值。用左值初始化另一个std::string对象时,编译器只会匹配拷贝构造函数,不会自动选择移动构造,毕竟编译器没法擅自判定你后续会不会再用到p_member,不会随便把它的资源转走。 - 只有通过
std::move(p_member)把它强制转换为将亡值(右值的一种),相当于你手动告诉编译器“这个形参之后不会再用了,可以转走它的资源”,初始化m_member时才会匹配到std::string的移动构造函数,直接把p_member内部持有的堆上字符串资源转移给m_member,省去逐字符拷贝的开销。
推荐写法
修改后的构造函数可以兼顾左右值传参的效率,不需要额外写左值const引用、右值引用两个重载版本,注意std::move定义在<utility>头文件中,需要手动引入:
#include <string> #include <utility> class Foo { public: Foo(std::string p_member) : m_member{std::move(p_member)} {} private: std::string m_member; }; int main() { Foo f{"Test"}; return 0; }
这种写法下,传左值进构造函数时总开销是1次拷贝+1次移动,传右值时总开销是2次移动,比传统的const std::string&传参后拷贝初始化成员的写法(传右值时是1次移动+1次拷贝)在传右值场景下效率更高,代码也更简洁。
内容的提问来源于stack exchange,提问作者josecgon
相关产品推荐
相关产品推荐

