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

C++原始指针类:拷贝赋值需释放旧内存?resize后需删旧数组?

关于C++原始指针成员的两个内存管理问题

问题一:拷贝赋值运算符中是否需要释放已分配的原始指针?

假设定义了如下包含原始指针成员的结构体struct_x,在拷贝赋值运算符中,当指针已经分配过内存时,是否需要先释放这些指针,再分配新的内存?

struct struct_x {
public:
    // 成员变量
    char*       m_arr = nullptr;
    size_t*     m_len = nullptr;
    size_t*     m_alloc_len = nullptr;

    // 默认构造函数
    struct_x() {
        m_len = new size_t(0);
        m_alloc_len = new size_t(0);
    }

    // 拷贝构造函数
    struct_x(const struct_x& x) {
        m_arr = new char[*x.m_alloc_len + 1];
        memcpy(m_arr, x.m_arr, *x.m_len);
        m_len = new size_t(*x.m_len);
        m_alloc_len = new size_t(*x.m_alloc_len);
    }

    // 拷贝赋值运算符
    void operator=(const struct_x& x) {
        // 这里是否需要先释放已分配的指针?
        // 比如:
        // if (m_arr != nullptr) { delete[] m_arr; }
        // if (m_len != nullptr) { delete m_len; }
        // if (m_alloc_len != nullptr) { delete m_alloc_len; }
        // 还是不需要?

        // 后续赋值操作...
    }
};

解答

必须先释放已分配的内存,否则会造成内存泄漏。

当前对象的m_arr、m_len、m_alloc_len已经指向堆上分配的内存,如果直接给这些指针重新赋值,原来的内存地址会丢失,再也无法被释放,最终变成内存泄漏。

另外要注意自我赋值的情况:如果用户执行obj = obj;,直接释放指针后再拷贝,会导致访问已经被释放的内存。正确做法是先判断是否是自我赋值,再执行释放和赋值:

void operator=(const struct_x& x) {
    // 先判断自我赋值
    if (this == &x) {
        return;
    }

    // 释放当前对象已有的内存
    delete[] m_arr;
    delete m_len;
    delete m_alloc_len;

    // 分配新内存并拷贝数据
    m_arr = new char[*x.m_alloc_len + 1];
    memcpy(m_arr, x.m_arr, *x.m_len);
    m_len = new size_t(*x.m_len);
    m_alloc_len = new size_t(*x.m_alloc_len);
}

(注:你提到的智能指针确实是更优选择,std::unique_ptr或std::shared_ptr会自动管理内存,避免手动释放的麻烦和错误。)


问题二:使用memmove后是否需要删除旧的m_arr?

在如下的resize函数中,使用memmove将旧数组的数据复制到新分配的数组后,是否需要删除旧的m_arr?

// 调整数组大小
void resize(const size_t& req_len) {
    using T = char; // 仅示例用
    if (req_len > *m_alloc_len) { // 修正:原代码中m_alloc_len是指针,需解引用
        if (*m_alloc_len == 0) { 
            *m_alloc_len = req_len; 
        }
        *m_alloc_len *= 16;
        T* l_arr = new T[*m_alloc_len + 1];
        memmove(l_arr, m_arr, *m_len); // 修正:m_len是指针,需解引用
        // 是否需要执行下面的删除操作?
        // if (m_arr != nullptr) { delete[] m_arr; }
        m_arr = l_arr;
    }
}

解答

必须删除旧的m_arr,否则会造成内存泄漏。

memmove只是把旧数组m_arr中的数据复制到新数组l_arr中,并没有释放旧数组占用的堆内存。如果不执行delete[] m_arr,旧数组的内存会一直留在堆中,且后续无法访问和释放,最终导致内存泄漏。

修正后的代码应该加上删除操作:

void resize(const size_t& req_len) {
    using T = char;
    if (req_len > *m_alloc_len) {
        if (*m_alloc_len == 0) { 
            *m_alloc_len = req_len; 
        }
        *m_alloc_len *= 16;
        T* l_arr = new T[*m_alloc_len + 1];
        if (m_arr != nullptr) { // 显式判断空指针,逻辑更清晰(delete[]空指针本身是安全的)
            memmove(l_arr, m_arr, *m_len);
            delete[] m_arr;
        }
        m_arr = l_arr;
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 15:24:25