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

基类指针指向派生类对象时的正确解构与删除方法问询

派生类指针赋值给基类指针后的正确析构与对象删除问题

当派生类指针赋值给基类指针后,如何正确析构派生类对象?同时能否以正确方式删除该派生类对象?以下是具体场景:

#include <stdio.h>
#include <iostream>
#include <map>
#include <stddef.h>


class Signal{
    public:
    Signal (int val) : x(val){};
    int x;
    
    virtual ~Signal(){
        std::cout<<"base class destructor"<<std::endl;
    }

};


class Timer : public Signal{
    public:
    Timer (int val) : Signal(val), y(val+1){};
    double y;  
    virtual ~Timer(){
        std::cout<<"derived class destructor"<<std::endl;
    };
};


int main()
{
    std::cout<<"start"<<std::endl;
    Timer* t = new Timer(9);
    Signal* s = t;
    
    delete s;
    std::cout<<t->x <<std::endl;
    std::cout<<t->y <<std::endl;
    s = NULL;


if (t != NULL){
    delete t;
}
    std::cout<<"end"<<std::endl;
    return 0;
}

代码执行输出:

start
derived class destructor
base class destructor
-340049904
10

...Program finished with exit code 0
Press ENTER to exit console.

已知避免Signal* s = t;赋值时程序可正常运行,但当前程序未打印预期的“end”,执行delete t时停止,无论是否添加t != NULL检查均是如此。


问题分析与解决方案

核心问题

代码触发了未定义行为:delete s已经释放了t指向的Timer对象内存,后续delete t属于对已释放内存的二次删除,这会导致程序崩溃或异常终止,因此无法执行到打印"end"的代码。另外,delete s后访问t->x和t->y属于访问野指针,结果是随机的(比如x的垃圾值)。

正确的处理方式

  1. 仅删除一次对象
    由于s和t指向同一个堆对象,只需要调用一次delete即可。因为你已经将基类的析构函数声明为virtual,通过基类指针delete s会自动先调用派生类Timer的析构函数,再调用基类Signal的析构函数,能完整清理派生类对象的所有资源。

    修正后的main函数示例:

    int main()
    {
        std::cout<<"start"<<std::endl;
        Timer* t = new Timer(9);
        Signal* s = t;
        
        // 一次delete即可完成完整析构
        delete s;
        // 或者使用 delete t; 效果完全相同
        
        // 禁止访问已释放内存的指针
        s = nullptr;
        t = nullptr;
        
        std::cout<<"end"<<std::endl;
        return 0;
    }
    
  2. 杜绝野指针操作
    对象被释放后,应立即将所有指向它的指针置为nullptr(C++11及以后推荐),避免后续误操作。

  3. 保持基类析构为虚函数
    这是多态场景下正确析构派生类的必要条件。如果基类析构不是虚函数,通过基类指针delete只会调用基类析构函数,派生类的成员资源不会被清理,造成内存泄漏。

为什么原代码没打印"end"

二次delete触发了未定义行为,程序在执行delete t时直接终止,因此后续的std::cout<<"end"<<std::endl;无法执行。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 02:05:20