如何修复C++中对象切割引发的内存泄漏问题?
问题分析与解决方案
首先,原代码存在几个核心问题:
- 基类
Foo未定义虚赋值运算符,导致*f = *b执行时会发生对象切片,仅调用Foo的默认赋值运算符(浅拷贝),无法正确处理Bar类的成员。 Foo和Bar的默认构造函数未初始化指针成员为nullptr,析构时可能触发未定义行为。- 你重载的
operator=逻辑不完整:既没有从other拷贝数据,也没有适配子类的多态场景,且j_使用的是当前对象的大小而非源对象的,无法实现真正的深拷贝。
正确实现方案
要实现*f = *b的多态深拷贝且避免内存泄漏,需要从以下几点入手:
1. 基类Foo添加虚赋值运算符
赋值运算符需要设为虚函数,确保通过基类指针调用时能触发子类的实现。同时完善深拷贝逻辑,释放原有内存后,正确拷贝源对象的数据。
2. 子类Bar重写赋值运算符
子类需要实现自己的赋值运算符,先处理基类部分的拷贝,再处理自身的成员变量,同时做类型检查保证安全。
完整修正代码:
#include <iostream> #include <algorithm> // 用于std::copy class Foo { public: // 默认构造函数初始化指针为nullptr,避免析构时的未定义行为 Foo() : i(nullptr), size_(0) {} Foo(int j) : size_(j) { i = new int[j](); // 初始化内存为0 } // 虚析构函数(保留原逻辑) virtual ~Foo() { delete[] i; } // 虚赋值运算符,支持多态 virtual Foo& operator=(const Foo& other) { if (this != &other) { // 先释放当前对象的内存 delete[] i; // 拷贝源对象的大小和数据 size_ = other.size_; i = new int[size_](); std::copy(other.i, other.i + size_, i); } return *this; } protected: int* i; int size_; // 保存数组大小,用于深拷贝 }; class Bar : public Foo { public: Bar(int j) : Foo(0) { // 基类部分初始化为空,因为Bar有独立的char数组 bar_i = new char[j](); bar_size_ = j; } ~Bar() override { delete[] bar_i; } // 重写赋值运算符,处理子类成员 Bar& operator=(const Foo& other) override { if (this != &other) { // 尝试将源对象转换为Bar类型,确保类型匹配 const Bar* bar_other = dynamic_cast<const Bar*>(&other); if (bar_other) { // 释放当前子类的内存 delete[] bar_i; // 重置基类部分的无效资源 delete[] i; i = nullptr; size_ = 0; // 深拷贝Bar的成员数据 bar_size_ = bar_other->bar_size_; bar_i = new char[bar_size_](); std::copy(bar_other->bar_i, bar_other->bar_i + bar_size_, bar_i); } else { // 源对象不是Bar类型,调用基类的赋值逻辑 Foo::operator=(other); } } return *this; } private: char* bar_i; int bar_size_; }; int main() { int i = 5, j = 10; Foo* f = new Foo(i); Foo* b = new Bar(j); *f = *b; // 现在会调用Bar的operator=,实现正确深拷贝 delete f; delete b; }
关键细节说明
- 虚赋值运算符:基类
Foo的operator=设为virtual,子类Bar重写后,通过基类指针调用时会触发子类的实现,彻底避免对象切片问题。 - 内存安全:赋值时先释放当前对象的原有内存,再分配新内存并拷贝数据,从根源避免内存泄漏。
- 类型检查:在
Bar的赋值运算符中使用dynamic_cast验证源对象类型,确保只有当源对象是Bar时才处理子类专属成员,否则回退到基类逻辑。 - 初始化规范:所有构造函数都初始化指针成员为
nullptr或分配内存时默认初始化,避免析构时的未定义行为。
内容的提问来源于stack exchange,提问作者mascai
相关产品推荐
相关产品推荐

