C++指针编程你要小心的陷阱——如何优雅的释放指针void*

指针操作是C++开发中必备技能。尽管C++11开始引入了智能指针以缓解普通指针的滥用,但是某些场合必须使用普通指针。释放指针在C/C++编程中非常重要,一般推荐释放指针后立即将指针设置为null,防止出现低级的野指针问题(只能避免低级别的野指针)同时方便调试。
一、C语言时代
在C语言编程中,我们由于没有C++模板,函数重载功能,所以一般定义一个统一的宏来用于释放指针。

// 删除指针    
#define SAFE_DELETE(p) { \    
    if (NULL != (p)) { \    
        free((p)); \    
        (p) = NULL;\    
    }\    
}   




二、C++时代
C++相对C语言的改进就是引入了面向对象操作,支持函数重载、类继承、模板、异常处理等等概念。在C++中,一般用函数模板来操作释放指针,这样的好处是可以进行类型检查。 view plai

// 删除数组  
template <typename T>  
inline void safe_delete(T *&target) {  
    if (nullptr != target) {  
        delete target;  
        target = nullptr;  
    }  
}  
  
// 删除数组指针  
template <typename T>  
inline void safe_delete_arr(T *&target) {  
    if (nullptr != target) {  
        delete[] target;  
        target = nullptr;  
    }  
} 




三、void *指针问题
在C、C++ 中,void * 指针可以转换为任意类型的指针类型,在删除void*指针时编译器往往会发出如下警告
warning: deleting 'void*' is undefined [enabled by default]
翻译:警告:删除“void *”指针可能引发未知情况(默认打开警告)
永远记住,在C、C++开发中绝对不能忽视警告,一定要重视警告,最好消除警告。有些警告无关紧要,有些警告却是bug的根源;删除void *指针的警告就属于后面一种情况,可能引起严重的bug而且难以发现:
1. 使用delete pointer; 释放void指针void *,系统会以释放普通指针(char, short, int, long, long long)的方式来释放void *指向的内存空间;
2. 如果void *指向一个数组指针,那么由于释放指针时用了delete pointer从而导致内存泄漏,释放指针正确做法是delete[] pointer;
3. 如果void *指向一个class类,那么系统由于认为void *指向一个普通的内存空间,所以释放指针时系统class的析构函数不会调用;

释放void *的解决方案:将void *转换为原来类型的指针,然后再调用delete释放指针,如果原来的指针是数组指针,那么必须使用delete []删除指向的内存空间。
在C++中我们可以使用模板定义内联函数:

template <typename T>  
inline void safe_delete_void_ptr(void *&target) {  
    if (nullptr != target) {  
        T* temp = static_cast<T*>(target);  
        delete temp;  
        temp = nullptr;  
        target = nullptr;  
    }  
}  




调用方法 view plain cop

int *psample = new int(100);  
safe_delete_void_ptr<int>(psample);



利用模板实例化参数统一简化过程。
测试代码
safe_delete_demo.cpp

#include <cstddef>  
#include <cstdlib>  
#include <string>  
#include <iostream>  
  
template <typename T>  
inline void safe_delete(T *&target) {  
    if (nullptr != target) {  
        delete target;  
        target = nullptr;  
    }  
}  
  
template <typename T>  
inline void safe_delete_void_ptr(void *&target) {  
    if (nullptr != target) {  
        T* temp = static_cast<T*>(target);  
        delete temp;  
        temp = nullptr;  
        target = nullptr;  
    }  
}  
  
class A {  
public:  
    A(std::string name) {  
        this->name = name;  
    };  
    virtual ~A() {  
        std::cout<<"base class A's destructor"<<", name: "<<this->name<<std::endl;  
    };  
public:  
    std::string name;  
};  
  
class AChild: public A {  
public:  
    AChild(std::string name, std::string school)  
    : A(name){  
        this->school = school;  
    };  
  
    ~AChild() {  
        std::cout<<"child class AChild's destructor"<<", name: "<<this->name  
            <<", school: "<<this->school<<std::endl;  
    };  
  
public:  
    std::string school;  
};  
  
int main(int argc, char *argv[]) {  
    // 测试safe_delete释放普通类指针  
    std::cout<<"safe_delete pointer of type AChild"<<std::endl;  
    AChild *a1 = new AChild("jacky", "Shenzhen University");  
    safe_delete(a1);  
    std::cout<<std::endl;  
  
    // 测试safe_delete释放void*指针  
    std::cout<<"safe_delete pointer of type void *"<<std::endl;  
    void *vp = new AChild("Polyn", "Southern University of Science and Technology");  
    safe_delete(vp);  
    std::cout<<std::endl;  
  
    // 测试safe_delete_void_ptr释放模板实例化为基类的void*指针  
    std::cout<<"safe_delete_void_ptr pointer of type void * ==> A *"<<std::endl;  
    void *vpA = new AChild("Heral", "Renmin University of China");  
    safe_delete_void_ptr<A>(vpA);  
    std::cout<<std::endl;  
  
    // 测试safe_delete_void_ptr释放模板实例化为子类的void*指针  
    std::cout<<"safe_delete_void_ptr pointer of type void * ==> AChild *"<<std::endl;  
    void *vpAChild = new AChild("pevly", "Southeast University");  
    safe_delete_void_ptr<AChild>(vpAChild);  
    return 0;  
}  




编译及运行
$ g++ -std=c++11 safe_delete_demo.cpp
safe_delete_demo.cpp: In instantiation of 'void safe_delete(T*&) [with T = void]':
safe_delete_demo.cpp:59:16: required from here
safe_delete_demo.cpp:9:9: warning: deleting 'void*' is undefined [enabled by default]
delete target;

$ ./a.out
safe_delete pointer of type AChild
child class AChild's destructor, name: jacky, school: Shenzhen University
base class A's destructor, name: jacky

safe_delete pointer of type void *
safe_delete_void_ptr pointer of type void * ==> A *
child class AChild's destructor, name: Heral, school: Renmin University of China
base class A's destructor, name: Heral

safe_delete_void_ptr pointer of type void * ==> AChild *
child class AChild's destructor, name: pevly, school: Southeast University
base class A's destructor, name: pevly

通过测试用例我们可以看出。
1. 使用safe_delete释放明确的类会自动触发析构函数(如果析构函数为虚函数,那么先调用子类的析构函数再调用子类的直接基类的析构函数);
2. 使用safe_delete释放void*指针指向的类时,不会触发对应类的析构函数;

3. 如果使用safe_delete_void_ptr内联函数释放void*指针,那么由于在释放指针前,函数会将void*指针转换为特定类型的函数指针,所以最终能够触发调用析构函数,并且不影响虚类的释放行为。





本文转自: 
http://blog.csdn.net/sweettool/article/details/77688337


  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园整体解决方案是响应国家教育信息化政策,结合教育改革和技术创新的产物。该方案以物联网、大数据、人工智能和移动互联技术为基础,旨在打造一个安全、高效、互动且环保的教育环境。方案强调从数字化校园向智慧校园的转变,通过自动数据采集、智能分析和按需服务,实现校园业务的智能化管理。 方案的总体设计原则包括应用至上、分层设计和互联互通,确保系统能够满足不同用户角色的需求,并实现数据和资源的整合与共享。框架设计涵盖了校园安全、管理、教学、环境等多个方面,构建了一个全面的校园应用生态系统。这包括智慧安全系统、校园身份识别、智能排课及选课系统、智慧学习系统、精品录播教室方案等,以支持个性化学习和教学评估。 建设内容突出了智慧安全和智慧管理的重要性。智慧安全管理通过分布式录播系统和紧急预案一键启动功能,增强校园安全预警和事件响应能力。智慧管理系统则利用物联网技术,实现人员和设备的智能管理,提高校园运营效率。 智慧教学部分,方案提供了智慧学习系统和精品录播教室方案,支持专业级学习硬件和智能化网络管理,促进个性化学习和教学资源的高效利用。同时,教学质量评估中心和资源应用平台的建设,旨在提升教学评估的科学性和教育资源的共享性。 智慧环境建设则侧重于基于物联网的设备管理,通过智慧教室管理系统实现教室环境的智能控制和能效管理,打造绿色、节能的校园环境。电子班牌和校园信息发布系统的建设,将作为智慧校园的核心和入口,提供教务、一卡通、图书馆等系统的集成信息。 总体而言,智慧校园整体解决方案通过集成先进技术,不仅提升了校园的信息化水平,而且优化了教学和管理流程,为学生、教师和家长提供了更加便捷、个性化的教育体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值