C++ 如何判断一个对象是否被删除、统一管理对象

文章目录

  • BUG
  • 解决方式
    • 完整测试例子

之前写了一篇:C++ 统一管理对象的删除,使用指针的指针**,或是指针的引用*&


BUG

其实发现这种写写法很有问题:
C++ 如何判断一个对象是否被删除、统一管理对象_第1张图片

因为如果一个对象被 delete 后,或是 free 后,随时都有可能会立刻被分配到其他地方的内存使用了。

所以 当前对象 this 或是 this 中的 char* _isDestroy 成员就有可能会被其他程序分配到一个我们这个程序中不可访问的内存地址中去,这时要是通过以下原来的判断方式就会出错:
C++ 如何判断一个对象是否被删除、统一管理对象_第2张图片

可能会报 this 内存地址不可访问。

那么也就是说,一旦我调用 bool isDestroy() 方法后,有可能都会报错,所以我们不能取访问一个野指针的 this 的内部数据了。


解决方式

使用一个 set 来记录对象内存地址即可
C++ 如何判断一个对象是否被删除、统一管理对象_第3张图片

声明一个 std::unorder_set,并在构造函数插入内存地址、在析构函数删除地址、在 isDestroy() 查询地址即可:
C++ 如何判断一个对象是否被删除、统一管理对象_第4张图片

这样就可以避开调用野指针 this 的内部数据调用,只是判断 this 地址是否在我们的管理对象的地址中即可。


完整测试例子

// jave.lin - 测试 Object 对象的统一管理删除
#include
#include
#include

// Check GCC
#if __GNUC__
#   pragma message("compiling in GNUC, GCC")
#   if __x86_64__ || __ppc64__
#       pragma message("64 bits computer")
#       define ENVIRONMENT64
#   else
#       pragma message("32 bits computer")
#       define ENVIRONMENT32
#   endif
#else
// Check windows
#   pragma message("compiling Not in GNUC, GCC")
#   if _WIN32 || _WIN64
#       pragma message("compiling in Window32/64")
#       if _WIN64
#           pragma message("64 bits computer")
#           define ENVIRONMENT64
#       else
#           pragma message("32 bits computer")
#           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 {
private:
    static std::unordered_set<address_t> objs_address;
public:
    // 使用引用指针,外部使用比较方便友好
    static void Destroy(Object*& obj);
    Object(std::string name = NULL);
    inline const bool isDestroy() const;
    const std::string getName() const;
protected:
    // 私有析构,只能从 Object::Destroy(Object*&) 销毁
    virtual ~Object();
private:
    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 实现
//
std::unordered_set<address_t> Object::objs_address;

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");
    objs_address.insert((address_t)this);
}

Object::~Object() {
    P("desctor");
    objs_address.erase((address_t)this);
}

inline const bool Object::isDestroy() const {
    return objs_address.find((address_t)this) != objs_address.end();
}

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";
    }
}

// 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";
    // }

    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() << "\n";
    }
    else {
        std::cout << "Holder->getObject() == NULL ";
    }
    Test_funs(holder);

    return 0;
}

/* 输出:
=== Testing obj ===
P6Object ctor : obj
After Object::Destroy(obj):
obj == NULL

=== Testing inheritor ===
P6Object ctor : inheritor
P9Inheritor ctor : inheritor
After Object::Destroy(inheritor):
inheritor == NULL

=== Testing Hold something ===
P6Object ctor : something
P6Object ctor : holder
P6Holder ctor : holder
After Object::Destroy(something):
something == NULL
Holder->getObject() != NULL , is destroy : 1
After Object::Destroy(holder):
holder == NULL
*/

你可能感兴趣的:(C/C++,判断一个对象是否没删除)