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

C++错误咨询:移动构造函数中使用已删除函数问题

解决C++中「Use of deleted function in move constructor」错误

Hey 伙计,咱们来拆解你碰到的这个移动构造函数相关的错误。先理清楚核心原因,再给你靠谱的解决办法:

错误根源

C++11及以后的标准里有个关键规则:当你显式定义了拷贝构造函数、拷贝赋值运算符、析构函数中的任意一个,编译器就会自动删除默认生成的移动构造函数和移动赋值运算符。

看你的代码,你已经写了Container(const Container & obj)这个拷贝构造函数(虽然没写完),所以编译器直接把默认的移动构造给禁用了。这时候如果你的代码里有需要触发移动构造的场景(比如用std::move转移对象,或者std::vector的扩容操作自动触发移动),编译器找不到可用的移动构造函数,就会抛出「使用已删除函数」的错误。

另外补充一句:你的类里用了裸指针int* m_Data,就算编译器没删移动构造,默认生成的版本也会做浅拷贝,很容易导致重复释放内存的问题——不过这是另一个坑,咱们先解决眼前的错误。

解决办法

针对这个问题,有两种主流方案,根据你的需求选择:

方案1:手动实现移动构造和移动赋值(推荐)

既然编译器把默认的删了,那咱们自己写一个符合语义的移动构造函数,直接转移资源而不是拷贝,既高效又安全:

// 移动构造函数,用noexcept告诉编译器不会抛出异常(容器操作会更高效)
Container(Container&& obj) noexcept : m_Data(obj.m_Data) {
    // 把源对象的指针置空,避免它析构时释放已经转移的资源
    obj.m_Data = nullptr;
    std::cout << "Move Constructor: Transferring resource" << std::endl;
}

同时建议配套实现移动赋值运算符,遵循C++的「五法则」:

Container& operator=(Container&& obj) noexcept {
    if (this != &obj) { // 防止自赋值
        // 先释放当前对象的资源
        delete[] m_Data;
        // 转移源对象的资源
        m_Data = obj.m_Data;
        obj.m_Data = nullptr;
        std::cout << "Move Assignment: Transferring resource" << std::endl;
    }
    return *this;
}

方案2:让编译器恢复默认移动构造(谨慎使用)

如果你确定代码里不会用到移动语义,或者想依赖编译器生成默认版本(但注意裸指针的浅拷贝风险),可以显式要求编译器生成:

// 显式声明默认移动构造和移动赋值
Container(Container&&) = default;
Container& operator=(Container&&) = default;

⚠️ 注意:这个方案只适合你能完全控制对象的生命周期,不会出现浅拷贝导致的double free问题的场景,一般更推荐方案1。

额外补充:完善你的拷贝构造函数

你的代码里拷贝构造函数的for循环没写完,记得补全深拷贝逻辑,否则会有未定义行为:

Container(const Container & obj) {
    m_Data = new int[20];
    // 补全拷贝循环,完成深拷贝
    for (int i = 0; i < 20; ++i) {
        m_Data[i] = obj.m_Data[i];
    }
    std::cout << "Copy Constructor: Deep copying 20 int" << std::endl;
}

完整修正后的代码示例

#include<iostream>
#include<vector>

class Container {
    int * m_Data;
public:
    Container() {
        m_Data = new int[20];
        std::cout << "Constructor: Allocation 20 int" << std::endl;
    }

    ~Container() {
        if (m_Data) {
            delete[] m_Data;
            m_Data = nullptr; // 用nullptr代替NULL更符合C++11+规范
        }
        std::cout << "Destructor called" << std::endl;
    }

    // 深拷贝构造函数
    Container(const Container & obj) {
        m_Data = new int[20];
        for (int i = 0; i < 20; ++i) {
            m_Data[i] = obj.m_Data[i];
        }
        std::cout << "Copy Constructor: Deep copying 20 int" << std::endl;
    }

    // 拷贝赋值运算符
    Container& operator=(const Container& obj) {
        if (this != &obj) {
            delete[] m_Data;
            m_Data = new int[20];
            for (int i = 0; i < 20; ++i) {
                m_Data[i] = obj.m_Data[i];
            }
            std::cout << "Copy Assignment: Deep copying 20 int" << std::endl;
        }
        return *this;
    }

    // 移动构造函数
    Container(Container&& obj) noexcept : m_Data(obj.m_Data) {
        obj.m_Data = nullptr;
        std::cout << "Move Constructor: Transferring resource" << std::endl;
    }

    // 移动赋值运算符
    Container& operator=(Container&& obj) noexcept {
        if (this != &obj) {
            delete[] m_Data;
            m_Data = obj.m_Data;
            obj.m_Data = nullptr;
            std::cout << "Move Assignment: Transferring resource" << std::endl;
        }
        return *this;
    }
};

// 测试移动语义
int main() {
    Container c1;
    Container c2 = std::move(c1); // 触发移动构造
    Container c3;
    c3 = std::move(c2); // 触发移动赋值
    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 11:46:37