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

C++多态对象vector与unique_ptr内存泄漏问题咨询

关于C++多态内存管理与避免内存泄漏的疑问

问题背景

我在完成作业时尝试规范管理内存,遇到了一些疑问:

  • 想要创建存储父类、子类对象的vector,比如vector<Parent> list,知道需要用指针避免对象切割,所以考虑vector<Parent*>。
  • 了解到C++智能指针,但听说父类析构函数调用时(比如智能指针超出作用域)可能引发内存泄漏,不清楚怎么编写类来避免。

我写了一段示例代码,输出是"This is A",我认为这意味着通过指针调用析构函数会导致内存泄漏:

class A{
public:
    virtual void funct(){
        cout << "This is A" << endl;
    }
};
class B : public A{
public:
    void funct(){
        cout << "This is B" << endl;
    }
};

int main() {
    B b;

    auto ptr = make_unique<A>(b);

    ptr.get()->funct();

    return 0;
}

参考建议后修改了代码,给父类加了虚析构函数,子类也重写了析构函数,想问这样是否足以避免内存泄漏?也就是销毁unique_ptr ptr时,会不会释放B对象占用的内存?

class A{
public:
    virtual void funct(){
        cout << "This is A" << endl;
    };
    virtual ~A() = default;
};
class B : public A{
public:
    void funct() override{
        cout << "This is B" << endl;
    }
    
    ~B() override = default;
};

int main() {
    B b;

    unique_ptr<A> ptr = make_unique<B>(b);

    ptr->funct();

    return 0;
}

解答

第一段代码的核心问题

你第一段代码的问题不是析构导致的内存泄漏,而是对象切割:

  • make_unique<A>(b)是把B对象b拷贝构造了一个纯A类型的对象存到堆上,ptr指向的本质就是一个A对象,而非B对象,所以调用funct()只会触发A的版本,输出"This is A"。
  • 这里不存在子类内存未释放的问题,因为堆上本来就只有一个A对象,析构时只会调用A的析构函数,但这种写法完全没用到多态,根本达不到你存储子类对象的目的。

修改后的代码是否能避免内存泄漏

修改后的代码完全满足多态下安全释放内存的要求:

  1. 父类虚析构是核心:当父类析构函数被声明为虚函数时,通过父类指针/智能指针销毁子类对象时,会按正确顺序调用子类→父类的析构函数,确保所有层级的资源都被释放。
  2. 你给A添加virtual ~A() = default;,同时给B的析构函数加上override关键字的写法非常规范——override能确保你确实重写了父类的虚析构,避免拼写错误导致的意外问题。
  3. 这段代码中make_unique<B>(b)是在堆上构造了一个B对象(拷贝自栈上的b),unique_ptr<A>指向这个B对象。当ptr超出作用域时,会先调用B的析构函数,再调用A的析构函数,完全释放B对象占用的所有内存,不会产生内存泄漏。

补充建议

  • 如果要在容器中存储多态对象,推荐使用vector<unique_ptr<A>>而非裸指针,容器销毁时会自动释放所有元素的内存,无需手动管理。
  • 永远避免直接用父类类型构造子类对象,这种操作会触发对象切割,丢失子类特性,也无法实现多态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 16:20:02