添加noexcept后Move Constructor触发Debug Assertion Failed,求排查
移动构造函数触发Debug Assertion Failed问题排查
我正在练习移动构造函数,定义了VectorContainer类并实现了拷贝构造函数和移动构造函数,但编译器一直调用拷贝构造函数而非移动构造函数。给移动构造函数加上noexcept关键字后,编译器终于调用移动构造函数了,却弹出了"Debug Assertion Failed"错误:
相关代码
类定义与成员函数实现
//Definition of Class VectorContainer class VectorContainer { private: double* elem; int sz; public: VectorContainer(int s) :elem{ new double[s] }, sz{ s } { SignifyCreation(); } ~VectorContainer() { delete[] elem; } void pushBack(double d, int a) { elem[a] = d; cout << "Element " << a << " has been set to " << elem[a] << endl; } void SignifyCreation() { cout << "A VectorContainer Object has been created " << endl; } VectorContainer(const VectorContainer& vc); VectorContainer* operator=(const VectorContainer& vc); VectorContainer( VectorContainer&& vc) noexcept; //MOVE Constructor Declared const double operator[](int s) const { return elem[s]; } // Subscript Constant }; //COPY CONSTRUCTOR VectorContainer::VectorContainer(const VectorContainer& a) : elem{ new double[a.sz] }, sz{ a.sz } { for (int i = 0; i != a.sz; i++) { cout << "New Element[" << i << "]'s content was = " << elem[i] << endl; elem[i] = a[i]; cout << "Incoming Parameter " << i << "'s content is = " << a[0] << endl; cout << "New Element[" << i << "]'s content has now been set to = " << elem[i] << endl; } } //COPY ASSIGNMENT IMPLEMENTATION VectorContainer* VectorContainer::operator=(const VectorContainer& a) { double* p = new double[a.sz]; for (int i = 0; i != a.sz; i++) { p[i] = a[i]; } delete elem; elem = p; sz = a.sz; return this; } VectorContainer::VectorContainer(VectorContainer&& vc) noexcept :elem{ vc.elem }, sz{ vc.sz } { vc.elem = nullptr; vc.sz = 0; cout << "A VectorContainer Object has been MOVED " << endl; } VectorContainer& SpitVector() { VectorContainer vc10(2); vc10.pushBack(55.67, 0); vc10.pushBack(78.9, 1); return vc10; }
main函数代码
int main() { VectorContainer vc1(2); VectorContainer vc3(2); //To be copy assigned VectorContainer vc4(2); vc1.pushBack(45.67, 0); vc1.pushBack(20.78, 1); cout << "vc1 element 1 = " << vc1[0] << endl; cout << "vc1 element 2 = " << vc1[1] << endl; VectorContainer vc2(vc1); cout << "vc2 element 1 = " << vc2[0] << endl; cout << "vc2 element 2 = " << vc2[1] << endl; cout << "vc1 element 1 is still " << vc1[0] << endl; cout << "vc1 element 2 is still " << vc1[1] << endl; cout << "vc3's element 1 is " << vc3[0] << endl; cout << "vc3's element 2 is " << vc3[1] << endl; vc3 = vc2; ///???? Is this the right implementation of the Copy Assigment? cout << "vc3's element 1 is now " << vc3[0] << endl; cout << "vc3's element 2 is now " << vc3[1] << endl; VectorContainer vc5(move(SpitVector())); }
问题分析与修复
- 核心错误:返回局部对象的引用
SpitVector()函数返回VectorContainer&类型,但函数内部的vc10是局部对象,函数执行完毕后局部对象会被销毁,内存被释放。此时返回的引用是悬空引用,指向已经无效的内存。当用std::move处理这个悬空引用初始化vc5时,移动构造函数会尝试访问已销毁的vc10成员,直接触发调试断言失败。
修复方法:将SpitVector()的返回类型改为值返回VectorContainer,编译器会自动优化(或执行移动构造)返回对象,避免悬空引用:
VectorContainer SpitVector() { VectorContainer vc10(2); vc10.pushBack(55.67, 0); vc10.pushBack(78.9, 1); return vc10; }
- 拷贝赋值运算符返回值错误
当前拷贝赋值运算符返回VectorContainer*,但C++中赋值运算符的标准返回类型应为VectorContainer&,才能支持链式赋值(如a = b = c)。修改如下:
// 声明部分 VectorContainer& operator=(const VectorContainer& vc); // 实现部分 VectorContainer& VectorContainer::operator=(const VectorContainer& a) { if (this == &a) return *this; // 防止自赋值 double* p = new double[a.sz]; for (int i = 0; i != a.sz; i++) { p[i] = a[i]; } delete[] elem; // 对应new[],需用delete[]释放 elem = p; sz = a.sz; return *this; }
拷贝构造函数输出错误
拷贝构造函数中cout << "Incoming Parameter " << i << "'s content is = " << a[0] << endl;使用了a[0],应改为a[i],否则循环中始终输出第一个元素的值。关于移动构造函数的
noexcept
标准库容器(如std::vector)移动元素时,仅会调用noexcept的移动构造函数,否则会退而使用拷贝构造函数。你添加noexcept后编译器调用移动构造函数,这是符合预期的正确行为。
内容的提问来源于stack exchange,提问作者OldManChild
相关产品推荐
相关产品推荐

