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

📝 ✏️ 📌
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++中,一般用函数模板来操作释放指针,这样的好处是可以进行类型检查。// 删除数组template inline void safe_delete(T *&target) { if (nullptr != target) { delete target; target = nullptr; }} // 删除数组指针template 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 inline void safe_delete_void_ptr(void *&target) { if (nullptr != target) { T* temp = static_cast(target); delete temp; temp = nullptr; target = nullptr; }}调用方法int *psample = new int(100);safe_delete_void_ptr(psample);利用模板实例化参数统一简化过程。测试代码safe_delete_demo.cpp#include #include #include #include template inline void safe_delete(T *&target) { if (nullptr != target) { delete target; target = nullptr; }} template inline void safe_delete_void_ptr(void *&target) { if (nullptr != target) { T* temp = static_cast(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: "<name<school = school; }; ~AChild() { std::cout<<"child class AChild's destructor"<<", name: "<name <<", school: "<school< A *"<(vpA); std::cout< AChild *"<(vpAChild); return 0;}编译及运行$ g++ -std=c++11 safe_delete_demo.cppsafe_delete_demo.cpp: In instantiation of 'void safe_delete(T*&) [with T = void]':safe_delete_demo.cpp:59:16: required from heresafe_delete_demo.cpp:9:9: warning: deleting 'void*' is undefined [enabled by default]delete target;$ ./a.outsafe_delete pointer of type AChildchild class AChild's destructor, name: jacky, school: Shenzhen Universitybase class A's destructor, name: jackysafe_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 Chinabase class A's destructor, name: Heralsafe_delete_void_ptr pointer of type void * ==> AChild *child class AChild's destructor, name: pevly, school: Southeast Universitybase class A's destructor, name: pevly

通过测试用例我们可以看出。1. 使用safe_delete释放明确的类会自动触发析构函数(如果析构函数为虚函数,那么先调用子类的析构函数再调用子类的直接基类的析构函数);2. 使用safe_delete释放void*指针指向的类时,不会触发对应类的析构函数;3. 如果使用safe_delete_void_ptr内联函数释放void*指针,那么由于在释放指针前,函数会将void*指针转换为特定类型的函数指针,所以最终能够触发调用析构函数,并且不影响虚类的释放行为。————————————————

🔗 相关推荐

✨ 💡 🎯
火炬之光2总共几周目?
365网

火炬之光2总共几周目?

📅 07-13 👀 9854
再见了,铱星闪光!
开彩365下载安装

再见了,铱星闪光!

📅 08-15 👀 9049
梅西伟大且不可复制 35岁率阿根廷夺得世界杯冠军