You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++移动构造函数未被调用:代码实现何处出错?

问题

阅读Siddhartha Rao所著的C++书籍时,遇到如下代码,为验证移动构造函数的行为添加了输出语句,但运行时该语句未打印。程序输出仅显示两次构造和两次析构,未出现移动构造的日志,请问是否说明移动构造函数未被调用?代码实现存在哪些错误?

#include <iostream>
#include <algorithm>
using namespace std;

class MyBuffer
{
public:
 int* myNums;
 unsigned int bufLength;
 
 MyBuffer(unsigned int length)
 {
 bufLength = length;
 cout << "Constructor allocates " << length << " integers" << endl;
 myNums = new int[length]; // allocate memory
 }

 MyBuffer(const MyBuffer& src) // copy constructor
 {
 cout << "Copy constructor creating deep copy" << endl;
 bufLength = src.bufLength;
 myNums = new int[bufLength];
 copy(src.myNums, src.myNums + bufLength, myNums); // deep copy
 }

// move constructor
MyBuffer(MyBuffer&& moveSource)
{
cout << "Move constructor working here!" << endl;   
if(moveSource.myNums != NULL)
{
myNums = moveSource.myNums; // take ownership i.e. ’move’
moveSource.myNums = NULL; // set the move source to NULL
}
}

 ~MyBuffer()
 {
 cout << "Destructor releasing allocated memory" << endl;
 delete[] myNums; // free allocated memory
 }

 void SetValue(unsigned int index, int value)
 {
 if (index < bufLength) // check for bounds
 *(myNums + index) = value;
 }

 void DisplayBuf()
 {
 for (unsigned int counter = 0; counter < bufLength; ++counter)
 cout << *(myNums + counter) << " ";

 cout << endl;
 }
 };

MyBuffer Copy(MyBuffer& source) // function
{
MyBuffer copyForReturn(source.bufLength); // create copy
return copyForReturn; // return by value invokes copy constructor
} 

int main()
{
MyBuffer buf1(5);
MyBuffer buf2 = Copy(buf1); // invokes 1x copy, 1x move constructor
return 0;
}

程序输出:

Constructor allocates 5 integers Constructor allocates 5 integers Destructor releasing allocated memory Destructor releasing allocated memory

分析与修正

1. 移动构造函数未被调用的原因

是的,移动构造函数确实没被调用,核心原因是编译器触发了命名返回值优化(NRVO):
在Copy函数中,局部对象copyForReturn是直接返回的命名对象,编译器会跳过"构造局部对象→移动/拷贝到返回值→析构局部对象"的流程,直接在main函数中buf2的内存位置构造copyForReturn,因此不需要调用移动或拷贝构造函数。

如果要强制观察移动构造的行为,可以关闭返回值优化:

  • GCC/Clang编译时添加参数:-fno-elide-constructors
  • MSVC编译时添加参数:/Zc:nrvo-(仅禁用命名返回值优化)或/Od(禁用所有优化)

关闭优化后,程序会调用移动构造函数,输出中会出现Move constructor working here!的日志。

2. 代码中的错误

(1) 移动构造函数未处理bufLength

原移动构造函数只接管了myNums指针,但未将moveSource.bufLength赋值给当前对象的bufLength,导致移动后的对象bufLength为未初始化的垃圾值,后续调用DisplayBuf、SetValue等成员函数会触发越界或未定义行为。

(2) 使用C风格NULL而非C++11的nullptr

NULL本质是宏定义(通常为0),在C++11及以后推荐使用类型安全的nullptr表示空指针。

(3) 移动构造函数未标记noexcept(可选但推荐)

移动构造函数通常不会抛出异常,标记noexcept能让标准库容器(如vector)在重新分配内存时优先选择移动而非拷贝,提升性能。

修正后的移动构造函数

// 修正后的移动构造函数
MyBuffer(MyBuffer&& moveSource) noexcept
{
    cout << "Move constructor working here!" << endl;   
    // 接管内存和长度
    myNums = moveSource.myNums;
    bufLength = moveSource.bufLength;
    
    // 重置源对象,避免双重释放
    moveSource.myNums = nullptr;
    moveSource.bufLength = 0;
}

内容的提问来源于stack exchange,提问作者paapi_420

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 20:14:51