如何在C++中从vector删除shared_ptr持有的资源并按需重新引入
问题描述
我需要从vector中删除/销毁网络资源,必要时重新引入。为此写了测试程序,但在删除shared_ptr并置为nullptr时遇到问题:直接置为nullptr会导致悬空指针,怎么在不内存泄漏的情况下释放该位置?
测试代码:
#include <iostream> #include <vector> #include <memory> using namespace std; class ptr{ public: int x; ptr(int a):x(a){ } ~ptr() { cout << "destructor\n"; } }; int main() { std::vector<shared_ptr<ptr>>v; v.push_back(shared_ptr<ptr>(new ptr(100))); v.push_back(shared_ptr<ptr>(new ptr(200))); v.push_back(shared_ptr<ptr>(new ptr(300))); v.push_back(shared_ptr<ptr>(new ptr(400))); v.push_back(shared_ptr<ptr>(new ptr(500))); auto it = v.begin(); int i = 0; while(i < 5) { if((*it)->x == 300) { cout << "300 found \n"; delete (*it); // -> Problem is here. } it++; i++; } return 0; }
解决方案
你的核心问题是手动调用delete操作shared_ptr管理的对象,这完全违背了智能指针的设计初衷——shared_ptr会自动管理对象的生命周期,手动delete会导致重复释放,触发未定义行为。
正确的处理方式分两种场景:
场景1:彻底从vector中移除该元素
如果你不需要保留vector中的这个位置,直接用vector::erase删除迭代器指向的元素即可。erase会销毁这个shared_ptr,当shared_ptr的引用计数降为0时,自动调用对象的析构函数释放资源:
auto it = v.begin(); while (it != v.end()) { if ((*it)->x == 300) { cout << "300 found \n"; // 移除元素,同时shared_ptr销毁,自动释放对象 it = v.erase(it); } else { ++it; } }
场景2:保留vector中的位置,仅释放资源(置为nullptr)
如果需要保留vector的size,只是把该位置的资源释放,直接将shared_ptr赋值为nullptr即可。shared_ptr被置空时,引用计数减1,若计数为0则自动销毁对象,不会产生悬空指针:
auto it = v.begin(); int i = 0; while(i < 5) { if((*it)->x == 300) { cout << "300 found \n"; // 直接置空,shared_ptr自动管理资源释放 *it = nullptr; } it++; i++; }
问题根源解析
你手动delete (*it),相当于绕过shared_ptr直接释放了它管理的内存。但shared_ptr本身还持有这块内存的地址,当shared_ptr后续被销毁(比如vector析构时),会再次尝试释放这块已经被释放的内存,导致双重释放错误,这就是你遇到问题的核心原因。
内容的提问来源于stack exchange,提问作者Rasmi Ranjan Nayak
相关产品推荐
相关产品推荐

