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

