C++ vector中存放指针,从vector里面取出的一个指针应该释放空间吗?

探讨了在C++中如何正确地在vector中管理动态分配的指针,避免重复释放内存导致的程序崩溃。

零、小序

vector是C++程序员经常使用的一种序列化容器,可以说C++程序员每天都在使用,vector中可以存放各种类型的数据,使用起来简单方便。vector用来存放指针这不是一个新鲜事,vector释放空间也不是新鲜事,那么从vector中单独取出来一个指针,这个指针使用完需要单独释放空间吗?你知道吗?不知道的来看看,知道的绕道吧。

一、先来看一段代码

1、代码示例

// TestArray2.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <vector>

using namespace std;

class Person
{
public:
	int age;
};

int main()
{
	vector<Person*> tmpVector;
	for (int i=1; i<10; ++i)
	{
		Person *pPerson = new Person;
		pPerson->age = i;
		tmpVector.emplace_back(pPerson);
	}

	Person *tmpPerson = tmpVector.at(0);
	if (tmpPerson != nullptr)
	{
		delete tmpPerson;
		tmpPerson = nullptr;
	}
	for (auto iter=tmpVector.begin(); iter!=tmpVector.end(); ++iter)
	{
		if (*iter != nullptr)
		{
			delete (*iter);
			(*iter) = nullptr;
		}
	}
	// 清空vector数据并释放空间
	tmpVector.clear();
	vector<Person*> tmpSwapVector;
	tmpSwapVector.swap(tmpVector);

    std::cout << "Hello World!\n";
	getchar();
}

2、这段代码能正常运行吗

答案:当然是不能的!而且程序会崩溃!原因就是从vector中取出的tmpPerson单独释放了空间,导致tmpVector中存储的第一个指针变成了野指针,tmpPerson和tmpVector[0]指向的是同一块内存地址,同一块地址释放两次空间肯定会崩溃的!只需要在tmpVector中释放空间就可以了。

3、运行现象

VS2017下面,可以看到崩溃了,并且自动跳转到和内存释放的代码库中。
在这里插入图片描述

二、正确的示范

下面的代码中使用条件编译把有问题的代码注释掉了,并加了注释说明。

// TestArray2.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <vector>

using namespace std;

class Person
{
public:
	int age;
};

int main()
{
	vector<Person*> tmpVector;
	for (int i=1; i<10; ++i)
	{
		Person *pPerson = new Person;
		pPerson->age = i;
		tmpVector.emplace_back(pPerson);
	}
	cout << "-------------打印vector中所有指针的地址------------" << endl;
	for (auto iter : tmpVector)
	{
		cout << iter << endl;
	}

	cout << "-------------打印从vector中取出的指针的地址------------" << endl;
	Person *tmpPerson = tmpVector.at(0);
	cout << tmpPerson << endl;

#if 0
	// 这里不需要释放,后面释放数组中的空间就可以了
	// 如果在这里释放的话,vector的第一个指针会变成野指针,后面再释放vector空间时程序会崩溃
	if (tmpPerson != nullptr)
	{
		delete tmpPerson;
		tmpPerson = nullptr;
	}
#endif
	
	for (auto iter=tmpVector.begin(); iter!=tmpVector.end(); ++iter)
	{
		if (*iter != nullptr)
		{
			delete (*iter);
			(*iter) = nullptr;
		}
	}
	// 清空vector数据并释放空间
	tmpVector.clear();
	vector<Person*> tmpSwapVector;
	tmpSwapVector.swap(tmpVector);

    std::cout << "Hello World!\n";
	getchar();
}

运行结果:
在这里插入图片描述

能力有限,如有错误,多多指教!原创不易,点赞鼓励一下吧!

C++03 中,当 `std::vector` 存储的是指针时,`erase` 操作本身不会自动释放指针指向的内存[^1]。这是因为 `std::vector` 仅负责管理其内部存储的指针本身的生命周期,而不是指针所指向的对象的生命周期。因此,在调用 `erase` 之前,如果希望释放指针指向的资源,则需要显式地调用 `delete` 来释放内存。 例如,假设有一个 `std::vector<int*>`,其中存储了动态分配的整数指针,那么在 `erase` 之前释放内存的代码可以如下: ```cpp std::vector<int*> vec; vec.push_back(new int(10)); // 在 erase 前手动释放内存 for (std::vector<int*>::iterator it = vec.begin(); it != vec.end(); ++it) { delete *it; // 释放指针指向的对象 } vec.erase(vec.begin()); // 然后 erase 指针本身 ``` 需要注意的是,`erase` 操作之后,被移除的元素(即指针)将不再存在于 `vector` 中,但 `vector` 本身不会对指针指向的对象进行任何操作。因此,如果未在 `erase` 前释放内存,会导致内存泄漏。 此外,为了确保程序的健壮性,建议在释放内存后将指针设置为 `NULL`,以避免出现悬空指针(dangling pointer)。但由于 `std::vector` 中的指针在 `erase` 后会被直接移除,因此在这种情况下设置 `NULL` 可能并不必要,除非在 `erase` 之前已经释放了内存。 ### 优化建议 为了避免手动管理内存带来的复杂性和潜在的错误,可以考虑使用智能指针(如 `boost::shared_ptr` 或 C++11 及以后版本中的 `std::shared_ptr`)来替代原始指针[^1]。这样,内存的释放将由智能指针自动管理,无需手动调用 `delete`。 例如: ```cpp #include <boost/shared_ptr.hpp> #include <vector> std::vector<boost::shared_ptr<int>> vec; vec.push_back(boost::shared_ptr<int>(new int(10))); vec.erase(vec.begin()); // erase 时无需手动 delete ``` 在这种情况下,`boost::shared_ptr` 会在其引用计数变为零时自动释放内存,从而避免了内存泄漏。 ### 总结 在 C++03 中,当 `std::vector` 存储的是原始指针时,在 `erase` 操作前必须手动调用 `delete` 来释放指针指向的内存,否则会导致内存泄漏。此外,使用智能指针可以简化内存管理并提高代码的安全性。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值