为什么移动构造函数没有被调用?
我来帮你拆解这个问题,你之所以看不到移动构造函数被调用,主要有两个核心原因:
1. 你的代码触发的是「参数化构造函数」,而非移动构造的场景
先看这句关键代码:
Mystring larry2 = "some larry";
这里的右操作数是字符串字面量"some larry",它的原生类型是const char[11],会自动退化为const char*。而你的移动构造函数Mystring::Mystring(Mystring &&source)只接受**Mystring类型的右值**,根本不处理const char*类型的输入。
所以编译器的第一步动作是:调用你的参数化构造函数(Mystring(const char*)),把const char*转换成一个临时的Mystring对象。
2. 编译器的「拷贝消除」优化跳过了移动步骤
按照C++的原始规则,在临时对象创建完成后,应该用这个临时对象(它是Mystring的右值)调用移动构造函数来初始化larry2。但几乎所有现代编译器都会触发**拷贝消除(Copy Elision)**优化——简单说就是编译器会直接跳过临时对象的创建,直接用参数化构造函数初始化larry2,完全省去了移动的环节。
这就是你只看到「param ctor called」输出的原因。
怎么验证移动构造确实能被触发?
如果你想看到移动构造函数被调用的场景,可以做这两个尝试:
尝试1:显式生成Mystring右值,关闭编译器优化
比如修改代码为:
Mystring larry2 = Mystring("some larry");
然后在编译时关闭拷贝消除优化(比如GCC/Clang用-fno-elide-constructors参数),这时你会看到输出顺序是:
param ctor called move ctor called dtor called: some larry // 临时对象的析构 ...
尝试2:对已有的Mystring对象使用std::move
比如:
Mystring temp("temp string"); Mystring larry3 = std::move(temp); // 这里一定会触发移动构造
std::move的作用是把temp这个左值强制转换成Mystring&&类型的右值,这时编译器就会调用你的移动构造函数来初始化larry3。
额外补充
你可能误以为字符串字面量会直接触发移动构造,但记住:移动构造函数的核心是转移已有Mystring对象的资源,而不是从原始字符串字面量创建新对象。从const char*创建Mystring的工作,本来就该是参数化构造函数的职责哦。
备注:内容来源于stack exchange,提问作者gaurav s

