C++ 统一管理对象的删除,使用指针的指针**,或是指针的引用*&
程序员文章站
2022-06-16 19:54:06
懒得动写字了,直接贴多一些代码吧。主要是使用 指针的指针 或是 指针的引用,这里使用的是后者 指针的引用,因为这样函数的外部调用和内部代码编写起来会友好一些。指针的引用 只要考虑使用起来会比较安全一些,毕竟 引用参数(实参) 是必须传入一个 左值,就是要有一个指针对象传入,不能留空。简单的测试// jave.linvoid my_alloc(int*& ptr_ref) { ptr_ref = new int(99);}void my_free(int*& ptr_re...
懒得动写字了,直接贴多一些 代码 与 注释吧。
主要是使用 指针的指针 或是 指针的引用,这里使用的是后者 指针的引用,因为这样函数的外部调用和内部代码编写起来会友好一些。
指针的引用 只要考虑使用起来会比较安全一些,毕竟 引用参数(实参) 是必须传入一个 左值,就是要有一个指针对象传入,不能留空。
简单的测试
// 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 NULL\n";
}
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 NULL\n";
}
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 << " == NULL\n";
}
else {
std::cout << backup_name << " != NULL\n";
}
}
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
本文地址:https://blog.csdn.net/linjf520/article/details/107293123