C++中数组内指针无法通过函数置为NULL的问题排查
先看你的代码场景:你在Modal里定义了A* obj1和B* obj2,写了个remove函数通过引用把指针置为NULL,直接调用remove(obj1)完全正常,但把它们放进数组遍历调用就完全没效果。问题核心在于数组里存的是原指针的副本,循环里操作的也是副本,根本碰不到Modal里的原指针。
具体原因拆解:
数组初始化的拷贝行为
当你写A* objects[] = { obj1, obj2 };时,数组的每个元素都是独立的指针变量——它们只是把obj1和obj2当前的地址值复制了一份存进去,数组元素和Modal里的obj1、obj2是完全无关的两个东西。范围for循环的变量拷贝
再看for(auto obj: objects),这里的obj是数组元素的临时拷贝,每次循环都会创建一个新的A*变量,它等于数组里的元素值。哪怕你把obj传给remove函数(参数是A*&),绑定的也是这个临时变量的引用,修改的只是这个临时变量为NULL,原obj1、obj2根本不会被影响。
解决方法(按简洁度排序)
方案1:用折叠表达式直接批量处理(C++17+推荐)
如果后续要加更多指针,直接把所有指针作为参数传给一个lambda,用折叠表达式自动遍历调用remove,完全不用数组,代码最简洁易维护:
// 在Modal的析构函数里 auto clearAll = [this](auto&... ptrs) { (remove(ptrs), ...); // 折叠表达式,依次调用remove处理每个指针 }; clearAll(obj1, obj2); // 后续加新指针,直接在这里追加参数就行
方案2:用指针的指针数组
既然要操作原指针,就存原指针的地址(也就是指针的指针),这样遍历的时候操作的是原指针的地址,就能修改原指针的值了:
// 注意obj2是B*,单继承下用reinterpret_cast转成A**是安全的 A** objects[] = { &obj1, reinterpret_cast<A**>(&obj2) }; for(auto ptrAddr : objects) { remove(*ptrAddr); // 解引用得到原指针的引用,传给remove }
方案3:用std::reference_wrapper存指针引用
C++不能直接创建引用数组,但可以用std::reference_wrapper包装指针的引用,让数组里存的是原指针的“引用代理”:
#include <functional> // 需包含该头文件 // 在Modal里 std::reference_wrapper<A*> objects[] = { obj1, obj2 }; for(auto& ref : objects) { remove(ref.get()); // get()返回原指针的引用,传给remove }
以上方案都能实现批量修改原指针的需求,后续新增对象时也能轻松扩展代码。
内容的提问来源于stack exchange,提问作者L3M0L

