其实发现这种写写法很有问题:
因为如果一个对象被 delete 后,或是 free 后,随时都有可能会立刻被分配到其他地方的内存使用了。
所以 当前对象 this 或是 this 中的 char* _isDestroy 成员就有可能会被其他程序分配到一个我们这个程序中不可访问的内存地址中去,这时要是通过以下原来的判断方式就会出错:
可能会报 this 内存地址不可访问。
那么也就是说,一旦我调用 bool isDestroy() 方法后,有可能都会报错,所以我们不能取访问一个野指针的 this 的内部数据了。
使用一个 set 来记录对象内存地址即可
声明一个 std::unorder_set<address_t> ,并在构造函数插入内存地址、在析构函数删除地址、在 isDestroy() 查询地址即可:
std::unorder_set<address_t>
这样就可以避开调用野指针 this 的内部数据调用,只是判断 this 地址是否在我们的管理对象的地址中即可。
// jave.lin - 测试 Object 对象的统一管理删除 #include<iostream> #include<typeinfo> #include<unordered_set> // 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 文章目录BUG解决方式完整测试例子之前写了一篇:C++ 统一管理对象的删除,使用指针的指针**,或是指针的引用*&BUG其实发现这种写写法很有问题:因为如果一个对象被 delete 后,或是 free 后,随时都有可能会立刻被分配到其他地方的内存使用了。所以 当前对象 this 或是 this 中的 char* _isDestroy 成员就有可能会被其他程序分配到一个我们这个程序中不可访问的内存地址中去,这时要是通过以下原来的判断方式就会出错:可能会报 this 内存地址不可访问。 代码如下:#include<sys>#include<unistd>int is_dir(char *path){ struct stat buf; if(lstat(path , &buf) < 0){ return FALSE; } int ret = __S_IFDIR & buf.st_mode; if(ret){ return TRUE; } return FALSE;} 您可能感兴趣的文章:VC++获得当前进程运行目录的方法C++递归删除一个目录实例C++检查某个文件或目录是否存在的函数C/ Delete 可以通过使用Delete 运算符或Delete [ ] 运算符来使用 New 运算符用于动态内存分配,将变量放在堆内存上。 这意味着 Delete 运算符从堆中释放内存。 指向对象的指针不被销毁,指针指向的值或内存块被销毁。 delete 运算符具有void返回类型,不返回值。 Delete is anoperatorthat is used to... 在帖子如何判断一个C++对象是否在堆栈上 中, 又有人提出如何判断一个C++对象是否在堆上。其实我们可以参照那个帖子的方法类似实现,我们知道堆就是Heap,在windows上我们可以通过GetProcessHeaps来得到所有的堆句柄,而我们这里只要知道Windows上的Heap Handle,其实就是堆的起始地址,就可以写如下代码了。 #include <iostream> 在C++中delete指针前不用进行指针是否为空的判断,因为delete的实现已经做了这件事情! 使用delete来delete已释放的指针是一个严重的错误,所以要在delete完一个指针后手动把它置空! 因为delete空指针是安全的。 以下是Bjarne Stroustrup's C++ Style and Technique FAQ中的 Why does 在C ++中删除设置为NULL的指针时会发生什么? 值得庆幸的是,什么都没有! delete将检查指针是否为NULL,如果发现该对象设置为NULL,则跳过该对象的删除。 2.delete对象和对象数组 如果delete-expression的操作数的值不是空指针值,则delete-expression将为要删除的对象或数组元素调用析构函数(如果有)。... 1. 源文章 为何new出的对象数组必须要用delete[]删除,而普通数组delete和delete[]都一样-------_CrtMemBlockHeader 先看了这篇由同事推荐的文章,让我对new时申请内存时具体做的时候所了解。 对于delete,验证了对象数组 用 delete 删除不行(因为对象数组中还有一个元素大小4个字... Unity - 撸一个简单版本的 四叉树 + 视锥cascaded + 多线程按分类剔除 + GPU instancing,用于场景剔除 (还有BUG,后续再优化) banner1990: 求一个百度网盘密码 OpenGL - TBO (Texture Buffer Object) - 缓存纹理 - Instancing Using TBO 前置篇 Jave.Lin: 已修正,tex_coord => buf_tex_coord OpenGL - TBO (Texture Buffer Object) - 缓存纹理 - Instancing Using TBO 前置篇 年(・ิϖ・ิ)っ少!轻&狂: tex_coord这个是哪来的 C# Form.Show()方法 的一些线程内部特性 qq_38387255: 代码具体什么意思呢,看了完全不知道怎么用 Unity Shader - 在 URP 获取 Ambient(环境光) 颜色 盒盒盒子: 请问这个_GlossyEnvironmentColor.rgb是要引入什么吗?直接写好像会报错
// jave.lin - 测试 Object 对象的统一管理删除 #include<iostream> #include<typeinfo> #include<unordered_set> // 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 文章目录BUG解决方式完整测试例子之前写了一篇:C++ 统一管理对象的删除,使用指针的指针**,或是指针的引用*&BUG其实发现这种写写法很有问题:因为如果一个对象被 delete 后,或是 free 后,随时都有可能会立刻被分配到其他地方的内存使用了。所以 当前对象 this 或是 this 中的 char* _isDestroy 成员就有可能会被其他程序分配到一个我们这个程序中不可访问的内存地址中去,这时要是通过以下原来的判断方式就会出错:可能会报 this 内存地址不可访问。 代码如下:#include<sys>#include<unistd>int is_dir(char *path){ struct stat buf; if(lstat(path , &buf) < 0){ return FALSE; } int ret = __S_IFDIR & buf.st_mode; if(ret){ return TRUE; } return FALSE;} 您可能感兴趣的文章:VC++获得当前进程运行目录的方法C++递归删除一个目录实例C++检查某个文件或目录是否存在的函数C/ Delete 可以通过使用Delete 运算符或Delete [ ] 运算符来使用 New 运算符用于动态内存分配,将变量放在堆内存上。 这意味着 Delete 运算符从堆中释放内存。 指向对象的指针不被销毁,指针指向的值或内存块被销毁。 delete 运算符具有void返回类型,不返回值。 Delete is anoperatorthat is used to... 在帖子如何判断一个C++对象是否在堆栈上 中, 又有人提出如何判断一个C++对象是否在堆上。其实我们可以参照那个帖子的方法类似实现,我们知道堆就是Heap,在windows上我们可以通过GetProcessHeaps来得到所有的堆句柄,而我们这里只要知道Windows上的Heap Handle,其实就是堆的起始地址,就可以写如下代码了。 #include <iostream> 在C++中delete指针前不用进行指针是否为空的判断,因为delete的实现已经做了这件事情! 使用delete来delete已释放的指针是一个严重的错误,所以要在delete完一个指针后手动把它置空! 因为delete空指针是安全的。 以下是Bjarne Stroustrup's C++ Style and Technique FAQ中的 Why does 在C ++中删除设置为NULL的指针时会发生什么? 值得庆幸的是,什么都没有! delete将检查指针是否为NULL,如果发现该对象设置为NULL,则跳过该对象的删除。 2.delete对象和对象数组 如果delete-expression的操作数的值不是空指针值,则delete-expression将为要删除的对象或数组元素调用析构函数(如果有)。... 1. 源文章 为何new出的对象数组必须要用delete[]删除,而普通数组delete和delete[]都一样-------_CrtMemBlockHeader 先看了这篇由同事推荐的文章,让我对new时申请内存时具体做的时候所了解。 对于delete,验证了对象数组 用 delete 删除不行(因为对象数组中还有一个元素大小4个字...
Unity - 撸一个简单版本的 四叉树 + 视锥cascaded + 多线程按分类剔除 + GPU instancing,用于场景剔除 (还有BUG,后续再优化) banner1990: 求一个百度网盘密码 OpenGL - TBO (Texture Buffer Object) - 缓存纹理 - Instancing Using TBO 前置篇 Jave.Lin: 已修正,tex_coord => buf_tex_coord OpenGL - TBO (Texture Buffer Object) - 缓存纹理 - Instancing Using TBO 前置篇 年(・ิϖ・ิ)っ少!轻&狂: tex_coord这个是哪来的 C# Form.Show()方法 的一些线程内部特性 qq_38387255: 代码具体什么意思呢,看了完全不知道怎么用 Unity Shader - 在 URP 获取 Ambient(环境光) 颜色 盒盒盒子: 请问这个_GlossyEnvironmentColor.rgb是要引入什么吗?直接写好像会报错