懒得动写字了,直接贴多一些 代码 与 注释吧。
主要是使用 指针的指针 或是 指针的引用,这里使用的是后者 指针的引用,因为这样函数的外部调用和内部代码编写起来会友好一些。
指针的引用 只要考虑使用起来会比较安全一些,毕竟 引用参数(实参) 是必须传入一个 左值,就是要有一个指针对象传入,不能留空。
简单的测试
// jave.lin void my_alloc(int*& ptr_ref) { ptr_ref = new int(99); } void my_free(int*& ptr_ref) { if (ptr_ref != NULL) { delete ptr_ref; } ptr_ref = NULL; } int main() { int* ptr = NULL; my_alloc(ptr); std::cout << "after my_alloc(ptr);n"; if (ptr != NULL) { std::cout << "ptr is not NULL, *ptr : " << *ptr << "n"; } else { std::cout << "ptr is NULLn"; } std::cout << "after my_free(ptr);n"; my_free(ptr); if (ptr != NULL) { std::cout << "ptr is not NULL, *ptr : " << *ptr << "n"; } else { std::cout << "ptr is NULLn"; } return 0; } /* 输出: after my_alloc(ptr); ptr is not NULL, *ptr : 99 after my_free(ptr); ptr is NULL */
利用这一特性,我们可以将 类 的或是 结构体 的 析构函数 的访问级别 设置为protected
或是 private
,这样可以不对外使用。(不能 delete ptr;
来调用析构 或是 XXX::~XXX();
的方式来析构)
然后都只能统一一个函数来 Destroy(xxx)
,这样删除的业务逻辑的内聚性变高,维护性高一些。
注意下面我们又对 GCC 与 MSVC 下的编译器有做区别处理。
特别是某个Destroy 过后的对象之前,它在其他地方有引用是,值会在不同编译、运行平台下有所区别。
我将区别写在了注释,特别留意我的注释说明即可,这里就不想重复写说明了:
// jave.lin void my_alloc(int*& ptr_ref) { ptr_ref = new int(99); } void my_free(int*& ptr_ref) { if (ptr_ref != NULL) { delete ptr_ref; } ptr_ref = NULL; } class Holder { public: int* p_int_value = NULL; }; int main() { Holder h; int* ptr = NULL; my_alloc(ptr); h.p_int_value = ptr; my_free(ptr); // 这时虽然 ptr == NULL,但是 h.p_int_value != NULL,他在 MSVC 与 GCC,或是其他编译器的上的值是不同的,这里我处理了 MSVC 与 GCC 的情况,其他没考虑 #if GCC // GCC下直接判断h.p_int_value == NULL || *h.p_int_value == 0 if (h.p_int_value == NULL || *h.p_int_value == 0) { h.p_int_value = NULL; std::cout << "h.p_int_value destroy outside"; } #else // MSVC下就比较特殊,h.p_int_value // 既不是 NULL,*h.p_int_value 会调用异常 // 因为是h.p_int_value 地址是一个保护的、不可访问的地址:0xdddddddd // 所以判断需要调整 if (h.p_int_value == NULL || (uint32_t)h.p_int_value == 0xdddddddd || *h.p_int_value == 0) { h.p_int_value = NULL; std::cout << "h.p_int_value destroy outside"; } #endif return 0; }
完整测试代码
// jave.lin - 测试 Object 对象的统一管理删除 #include<iostream> #include<typeinfo> // Check GCC #if __GNUC__ # if __x86_64__ || __ppc64__ # define ENVIRONMENT64 # else # define ENVIRONMENT32 # endif #else // Check windows # if _WIN32 || _WIN64 # if _WIN64 # define ENVIRONMENT64 # else # define ENVIRONMENT32 # endif # endif #endif #ifdef ENVIRONMENT32 using address_t = unsigned int; #else using address_t = unsigned long long; #endif #define P(content) std::cout << typeid(this).name() << " " << content << " : " << getName() << "n" // // Object 声明 // class Object { public: // 使用引用指针,外部使用比较方便友好 static void Destroy(Object*& obj); Object(std::string name = NULL); inline const bool isDestroy() const; inline const bool isBDestroy() const; const std::string getName() const; protected: // 私有析构,只能从 Object::Destroy(Object*&) 销毁 virtual ~Object(); private: char* _isDestroy = NULL; bool _isBDestroy = false; std::string _name; }; // // Inherit 声明 // class Inheritor : public Object { public: Inheritor(std::string name = NULL); private: ~Inheritor(); }; // // Holder 声明 // class Holder : public Object { public: Holder(std::string name = NULL); inline void setObj(Object* obj); inline Object* getObj() const; private: ~Holder(); Object* _obj = NULL; }; // // Object 实现 // void Object::Destroy(Object*& obj) { // 拿到指针的引用,如果指针不为 NULL if (obj != NULL) { // 没有被执行过销毁 if (!(obj)->isDestroy()) { // 执行销毁 delete obj; // 在获取一次isDestroy(),看看输出信息 obj->isDestroy(); } // 将指针的引用赋值为 NULL obj = NULL; } } Object::Object(std::string name) : _name(name) { P("ctor"); _isDestroy = new char(0xFF); } Object::~Object() { P("desctor"); if (_isDestroy != NULL) { delete _isDestroy; _isDestroy = NULL; } _isBDestroy = true; } inline const bool Object::isDestroy() const { #if __GNUC__ std::cout << typeid(this).name(); std::cout << " _isDestroy == NULL : " << (_isDestroy == NULL); std::cout << ", *_isDestroy == 0 : " << (_isDestroy == NULL ? 0 : (*_isDestroy == 0)) << "n"; return _isDestroy == NULL || *_isDestroy == 0; #else std::cout << typeid(this).name(); std::cout << " _isDestroy == NULL : " << (bool)(_isDestroy == NULL); std::cout << ", (address_t)_isDestroy == 0xdddddddd : " << ((address_t)_isDestroy == 0xdddddddd); std::cout << ", *_isDestroy == 0 : " << (_isDestroy == NULL || ((address_t)_isDestroy == 0xdddddddd) ? 0 : (*_isDestroy == 0)) << "n"; return _isDestroy == NULL || (address_t)_isDestroy == 0xdddddddd || *_isDestroy == 0; #endif } inline const bool Object::isBDestroy() const { return _isBDestroy; } const std::string Object::getName() const { return _name; } // // Inheritor 实现 // Inheritor::Inheritor(std::string name) : Object(name) { P("ctor"); } Inheritor::~Inheritor() { P("desctor"); } // // Holder 实现 // Holder::Holder(std::string name) : Object(name) { P("ctor"); } Holder::~Holder() { P("desctor"); } inline void Holder::setObj(Object* obj) { _obj = obj; } inline Object* Holder::getObj() const { return _obj; } void Test_funs(Object* obj) { std::string backup_name = obj->getName(); // delete obj; // 私有接口就无法访问了,强制用户只用 Object::Destroy(Object*&) Object::Destroy(obj); // 对外部来说友好的接口 std::cout << "After Object::Destroy(" << backup_name << "):n"; if (obj == NULL) { std::cout << backup_name << " == NULLn"; } else { std::cout << backup_name << " != NULLn"; } } int main() { std::cout << "=== Testing obj ===n"; Object* obj = new Object("obj"); Test_funs(obj); std::cout << "n=== Testing inheritor ===n"; Inheritor* inht = new Inheritor("inheritor"); Test_funs(inht); std::cout << "n=== Testing Hold something ===n"; Object* something = new Object("something"); Holder* holder = new Holder("holder"); holder->setObj(something); Test_funs(something); if (holder->getObj() != NULL) { std::cout << "Holder->getObject() != NULL "; std::cout << ", is destroy : " << holder->getObj()->isDestroy(); std::cout << ", is bBDestroy : " << holder->getObj()->isBDestroy() << "n"; } else { std::cout << "Holder->getObject() == NULL "; } Test_funs(holder); return 0; } /* 输出: [VS2019] === Testing obj === class Object * ctor : obj class Object const * _isDestroy == NULL : 0, (address_t)_isDestroy == 0xdddddddd : 0, *_isDestroy == 0 : 0 class Object * desctor : obj class Object const * _isDestroy == NULL : 0, (address_t)_isDestroy == 0xdddddddd : 1, *_isDestroy == 0 : 0 After Object::Destroy(obj): obj == NULL === Testing inheritor === class Object * ctor : inheritor class Inheritor * ctor : inheritor class Object const * _isDestroy == NULL : 0, (address_t)_isDestroy == 0xdddddddd : 0, *_isDestroy == 0 : 0 class Inheritor * desctor : inheritor class Object * desctor : inheritor class Object const * _isDestroy == NULL : 0, (address_t)_isDestroy == 0xdddddddd : 1, *_isDestroy == 0 : 0 After Object::Destroy(inheritor): inheritor == NULL === Testing Hold something === class Object * ctor : something class Object * ctor : holder class Holder * ctor : holder class Object const * _isDestroy == NULL : 0, (address_t)_isDestroy == 0xdddddddd : 0, *_isDestroy == 0 : 0 class Object * desctor : something class Object const * _isDestroy == NULL : 0, (address_t)_isDestroy == 0xdddddddd : 1, *_isDestroy == 0 : 0 After Object::Destroy(something): something == NULL Holder->getObject() != NULL class Object const * _isDestroy == NULL : 0, (address_t)_isDestroy == 0xdddddddd : 1, *_isDestroy == 0 : 0 , is destroy : 1, is bBDestroy : 221 class Object const * _isDestroy == NULL : 0, (address_t)_isDestroy == 0xdddddddd : 0, *_isDestroy == 0 : 0 class Holder * desctor : holder class Object * desctor : holder class Object const * _isDestroy == NULL : 0, (address_t)_isDestroy == 0xdddddddd : 1, *_isDestroy == 0 : 0 After Object::Destroy(holder): holder == NULL [GCC] === Testing obj === P6Object ctor : obj PK6Object _isDestroy == NULL : 0, *_isDestroy == 0 : 0 P6Object desctor : obj PK6Object _isDestroy == NULL : 0, *_isDestroy == 0 : 0 After Object::Destroy(obj): obj == NULL === Testing inheritor === P6Object ctor : inheritor P9Inheritor ctor : inheritor PK6Object _isDestroy == NULL : 0, *_isDestroy == 0 : 0 P9Inheritor desctor : inheritor P6Object desctor : inheritor PK6Object _isDestroy == NULL : 0, *_isDestroy == 0 : 0 After Object::Destroy(inheritor): inheritor == NULL === Testing Hold something === P6Object ctor : something P6Object ctor : holder P6Holder ctor : holder PK6Object _isDestroy == NULL : 0, *_isDestroy == 0 : 0 P6Object desctor : something PK6Object _isDestroy == NULL : 0, *_isDestroy == 0 : 0 After Object::Destroy(something): something == NULL Holder->getObject() != NULL , is destroy : PK6Object _isDestroy == NULL : 0, *_isDestroy == 0 : 0 0, is bBDestroy : 1 PK6Object _isDestroy == NULL : 0, *_isDestroy == 0 : 0 P6Holder desctor : holder P6Object desctor : holder PK6Object _isDestroy == NULL : 1, *_isDestroy == 0 : 0 After Object::Destroy(holder): holder == NULL */
VS 下输出
=== Testing obj === class Object * ctor : obj class Object const * _isDestroy == NULL : 0, (address_t)_isDestroy == 0xdddddddd : 0, *_isDestroy == 0 : 0 class Object * desctor : obj class Object const * _isDestroy == NULL : 0, (address_t)_isDestroy == 0xdddddddd : 1, *_isDestroy == 0 : 0 After Object::Destroy(obj): obj == NULL === Testing inheritor === class Object * ctor : inheritor class Inheritor * ctor : inheritor class Object const * _isDestroy == NULL : 0, (address_t)_isDestroy == 0xdddddddd : 0, *_isDestroy == 0 : 0 class Inheritor * desctor : inheritor class Object * desctor : inheritor class Object const * _isDestroy == NULL : 0, (address_t)_isDestroy == 0xdddddddd : 1, *_isDestroy == 0 : 0 After Object::Destroy(inheritor): inheritor == NULL === Testing Hold something === class Object * ctor : something class Object * ctor : holder class Holder * ctor : holder class Object const * _isDestroy == NULL : 0, (address_t)_isDestroy == 0xdddddddd : 0, *_isDestroy == 0 : 0 class Object * desctor : something class Object const * _isDestroy == NULL : 0, (address_t)_isDestroy == 0xdddddddd : 1, *_isDestroy == 0 : 0 After Object::Destroy(something): something == NULL Holder->getObject() != NULL class Object const * _isDestroy == NULL : 0, (address_t)_isDestroy == 0xdddddddd : 1, *_isDestroy == 0 : 0 , is destroy : 1, is bBDestroy : 221 class Object const * _isDestroy == NULL : 0, (address_t)_isDestroy == 0xdddddddd : 0, *_isDestroy == 0 : 0 class Holder * desctor : holder class Object * desctor : holder class Object const * _isDestroy == NULL : 0, (address_t)_isDestroy == 0xdddddddd : 1, *_isDestroy == 0 : 0 After Object::Destroy(holder): holder == NULL
GCC 下输出
=== Testing obj === P6Object ctor : obj PK6Object _isDestroy == NULL : 0, *_isDestroy == 0 : 0 P6Object desctor : obj PK6Object _isDestroy == NULL : 0, *_isDestroy == 0 : 0 After Object::Destroy(obj): obj == NULL === Testing inheritor === P6Object ctor : inheritor P9Inheritor ctor : inheritor PK6Object _isDestroy == NULL : 0, *_isDestroy == 0 : 0 P9Inheritor desctor : inheritor P6Object desctor : inheritor PK6Object _isDestroy == NULL : 0, *_isDestroy == 0 : 0 After Object::Destroy(inheritor): inheritor == NULL === Testing Hold something === P6Object ctor : something P6Object ctor : holder P6Holder ctor : holder PK6Object _isDestroy == NULL : 0, *_isDestroy == 0 : 0 P6Object desctor : something PK6Object _isDestroy == NULL : 0, *_isDestroy == 0 : 0 After Object::Destroy(something): something == NULL Holder->getObject() != NULL , is destroy : PK6Object _isDestroy == NULL : 0, *_isDestroy == 0 : 0 0, is bBDestroy : 1 PK6Object _isDestroy == NULL : 0, *_isDestroy == 0 : 0 P6Holder desctor : holder P6Object desctor : holder PK6Object _isDestroy == NULL : 1, *_isDestroy == 0 : 0 After Object::Destroy(holder): holder == NULL
c/c++开发分享C++ 统一管理对象的删除,使用指针的指针**,或是指针的引用*&地址:https://blog.csdn.net/linjf520/article/details/107293123
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/599365.html