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

添加noexcept后Move Constructor触发Debug Assertion Failed,求排查

移动构造函数触发Debug Assertion Failed问题排查

我正在练习移动构造函数,定义了VectorContainer类并实现了拷贝构造函数和移动构造函数,但编译器一直调用拷贝构造函数而非移动构造函数。给移动构造函数加上noexcept关键字后,编译器终于调用移动构造函数了,却弹出了"Debug Assertion Failed"错误:
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()));
}

问题分析与修复

  1. 核心错误:返回局部对象的引用
    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;
}
  1. 拷贝赋值运算符返回值错误
    当前拷贝赋值运算符返回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;
}
  1. 拷贝构造函数输出错误
    拷贝构造函数中cout << "Incoming Parameter " << i << "'s content is = " << a[0] << endl;使用了a[0],应改为a[i],否则循环中始终输出第一个元素的值。

  2. 关于移动构造函数的noexcept
    标准库容器(如std::vector)移动元素时,仅会调用noexcept的移动构造函数,否则会退而使用拷贝构造函数。你添加noexcept后编译器调用移动构造函数,这是符合预期的正确行为。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.01 14:04:52