欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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