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
相关产品推荐
相关产品推荐

