C++新特性19_auto_ptr的使用及废除原因(已废除;两大缺陷:不能有两个auto_ptr 对象拥有同一个内部指针所有权;两个auto_ptr对象发生赋值操作时,右者对象会丧失该所有权;接口)

有了前面的基础,我们来看stl里提供了哪些智能指针以及是如何使用的,从最原始的C++98中添加的auto_ptr讲起。

1. class template: std::auto_ptr目前使用情况

template <class X> class auto_ptr;

从官网链接的文档上就可以看出,这个auto_ptr指针不推荐使用(deprecated),原因这里也有说明:

  • auto_ptr指针在c++11标准中就被废除了,可以使用unique_ptr来替代,功能上是相同的,unique_ptr相比较auto_ptr而言,提升了安全性(没有浅拷贝),增加了特性(delete析构)和对数组的支持。
  • 这个类模板提供了有限度的垃圾回收机制,通过将一个指针保存在auto_ptr对象中,当auto_ptr对象析构时,这个对象所保存的指针也会被析构掉。
  • auto_ptr 对象拥有其内部指针的所有权。这意味着auto_ptr对其内部指针的释放负责,即当自身被释放时,会在析构函数中自动的调用delete,从而释放内部指针的内存。

2 auto_ptr两大缺陷

2.1 auto_ptr下的模板类对象的多次析构

不能有两个auto_ptr 对象拥有同一个内部指针的所有权,因为有可能在某个时机,两者均会尝试析构这个内部指针

2.1.1 定义一个auto_ptr下的模板类对象

#include <iostream>
#include <memory>
using namespace std;

int main(int argc, char* argv[])
{
	//通过指针进行构造
	std::auto_ptr<int> aptr(new int(3));

	//一个取地址 一个拿内容 *aptr作为最原始的对象使用
	printf("aptr %p : %d\r\n", aptr.get(), *aptr);

	return 0;
}

在这里插入图片描述

2.1.2 同时对一个指针定义两个auto_ptr模板对象,两个对象都指向一个地址

#include <iostream>
#include <memory>
using namespace std;

int main(int argc, char* argv[])
{
	int*p = new int(3);

	{
		//通过指针进行构造
		std::auto_ptr<int> aptr1(p);
		std::auto_ptr<int> aptr2(p);
	}
	return 0;
}

下图中可以看到两个对象都指向了一个地址:
在这里插入图片描述
可以推测到一旦出了{}的块作用域,就会崩溃,这是因为一旦出作用域,对象就会析构,同一地址的对象析构两次就会造成崩溃。
在这里插入图片描述
这样的写法就与我们早期没有引用计数的指针类似。

2.2 两个auto_ptr对象发生赋值操作时,右者对象会丧失该所有权

两个auto_ptr对象之间发生赋值操作时,内部指针被拥有的所有权会发生转移,这意味着这个赋值的右者对象会丧失该所有权,不在指向这个内部指针(其会被设置成null指针)。

auto_ptr的构造的参数可以是一个指针,或者是另外一个auto_ptr对象。

  • auto_ptr获取了内部指针的所有权后,之前的拥有者会释放其所有权。
#include <iostream>
#include <memory>
using namespace std;

int main(int argc, char* argv[])
{
	{
		//通过指针进行构造
		std::auto_ptr<int> aptr1(new int(3));
		std::auto_ptr<int> aptr2(new int(111));
		aptr2 = aptr1;
		printf("aptr1 %p : %d\r\n", aptr1.get(), *aptr1);
	}

调试之后可以看到两个指针指向不同的地址
在这里插入图片描述
运行之后,aptr1的指针指向为empty,相当于aptr2的内容被释放,aptr1的内容被转移,等价于拷贝移动。
在这里插入图片描述

3. auto_ptr的接口(成员函数)

下来来查看auto_ptr的接口(成员函数)

3.1 auto_ptr析构及资源的自动释放release()

在这里可以在使用前调用release,从而放弃其内部指针的使用权,但是同样这么做违背了智能指针的初衷。


#include <iostream>
#include <memory>
using namespace std;

void foo_release()
{
	//释放
	int* pNew = new int(3);
	{
		std::auto_ptr<int> aptr(pNew);
		int* p = aptr.release();
	}

}

int main(int argc, char* argv[])
{
	foo_release();

	{
		//通过指针进行构造
		std::auto_ptr<int> aptr1(new int(3));
		std::auto_ptr<int> aptr2(new int(111));
		aptr2 = aptr1;
		printf("aptr1 %p : %d\r\n", aptr1.get(), *aptr1);
	}
	return 0;
}

在这里插入图片描述

3.2 分配新的指针所有权reset()

可以调用reset()来重新分配指针的所有权,reset中会先释放原来的内部指针的内存,然后分配新的内部指针。
在这里插入图片描述

3.3 =运算符的使用

void foo_assign()
{
    std::auto_ptr<int> p1;
    std::auto_ptr<int> p2;

    p1 = std::auto_ptr<int>(new int(3));
    *p1 = 4;
    p2 = p1;
}

4. 为什么11标准会不让使用auto_ptr,原因是其使用有问题。

4.1 作为参数传递会存在问题

因为有拷贝构造和赋值的情况下,会释放原有的对象的内部指针,所以当有函数使用的是auto_ptr时,调用后会导致原来的内部指针释放。

//p1内的值移动拷贝(剪切)给p,p1里的内容释放
void foo_test(std::auto_ptr<int> p)
{
    printf("%d\r\n", *p);
}

int _tmain(int argc, _TCHAR* argv[])
{
    //拷贝构造
    std::auto_ptr<int> p1 = std::auto_ptr<int>(new int(3));
    foo_test(p1);

    //这里的调用就会出错,因为拷贝构造函数的存在,p1实际上已经释放了其内部指针的所有权了
    printf("%d\r\n", *p1);

    return 0;
}

4.2 不能使用vector数组

数组传递值,本质也是移动拷贝

以下代码编译就无法通过

void foo_ary()
{
    std::vector<std::auto_ptr<int>> Ary;
    std::auto_ptr<int> p(new int(3));
    //push_back时不允许如此构造对象
    Ary.push_back(p);

    printf("%d\r\n", *p);
}

5. 学习视频地址:auto_ptr的使用及废除原因
6. 学习笔记:auto_ptr的使用及废除原因学习笔记

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
C++智能指针 智能指针 智能指针概念 C/C++ 语⾔最为⼈所诟病的特性之⼀就是存在内存泄露问题,因此后来的⼤多数语⾔都提供了内置内存分配与释放功能,有的甚⾄⼲脆对语 ⾔的使⽤者屏蔽了内存指针这⼀概念。这⾥不置贬褒,⼿动分配内存与⼿动释放内存有利也有弊,⾃动分配内存和⾃动释放内存亦如此,这 是两种不同的设计哲学。有⼈认为,内存如此重要的东西怎么能放⼼交给⽤户去管理呢?⽽另外⼀些⼈则认为,内存如此重要的东西怎么能 放⼼交给系统去管理呢?在 C/C++ 语⾔中,内存泄露的问题⼀直困扰着⼴⼤的开发者,因此各类库和⼯具的⼀直在努⼒尝试各种⽅法去检 测和避免内存泄露,如 boost,智能指针技术应运⽽⽣。 智能指针主要⽤于管理在堆上分配的内存,它将普通的指针封装为⼀个栈对象。当栈对象的⽣存周期结束后,在析构函数中释放掉申请的 内存,从⽽防⽌内存泄漏。简要的说,智能指针利⽤了 C++ 的 RAII 机制,在智能指针对象作⽤域结束后,⾃动做内存释放的相关操作, 不需要我们再⼿动去操作内存。 RAII是C++的发明者Bjarne Stroustrup提出的概念,RAII全称是"Resource Acquisition is Initialization",直译过来是"资源获取即初始化",也 就是说在构造函数中申请分配资源,在析构函数中释放资源。因为C++的语⾔机制保证了,当⼀个对象创建的候,⾃动调⽤构造函数,当 对象超出作⽤域的⾃动调⽤析构函数。所以,在RAII的指导下,我们应该使⽤类来管理资源,将资源和对象的⽣命周期绑定。 C++ 中有四种智能指针auto_pt、unique_ptr、shared_ptr、weak_ptr 其中后三个是 C++11 ⽀持,第⼀个已经被 C++11 弃⽤且被 unique_prt 代替,不推荐使⽤。下⽂将对其逐个说明。 std::auto_ptr 在这个年代讨论 std::auto_ptr 不免有点让⼈怀疑是不是有点过了,确实如此,随着 C++11 标准的出现(最新标准是 C++20),std::auto_ptr 已经被彻底放弃,取⽽代之是 std::unique_ptr。然⽽,之所以还向介绍⼀下 std::auto_ptr 的⽤法以及它的设计不⾜ 之处是想更多了解 C++ 语⾔中智能指针的发展过程,⼀项技术如果我们了解它过去的样⼦和发展的轨迹,我们就能更好地掌握它。 std::auto_ptr 的基本⽤法如下代码所⽰: #include <iostream> #include <memory> using namespace std; int main() { //初始化⽅式1 std::auto_ptr<int> ap1(new int(8)); //初始化⽅式2 std::auto_ptr<int> ap2; ap2.reset(new int(8)); cout << *ap1 << ", " << *ap2 << endl; return 0; } 输出: 8, 8 智能指针对象 ap1 和 ap2 均持有⼀个在堆上分配 int 对象,其值均是 8,这两块堆内存均可以在 ap1 和 ap2 释放得到释放。这是 std::auto_ptr 的基本⽤法。 std::auto_ptr 真正让⼈容易误⽤的地⽅是其不常⽤的复制语义,即当复制⼀个 std::auto_ptr 对象(拷贝复制或 operator= 复制),原对象 所持有的堆内存对象转移给复制出来的对象。⽰例代码如下: #include <memory> int main() { //测试拷贝构造 std::auto_ptr<int> ap1(new int(8)); std::auto_ptr<int> ap2(ap1); if (ap1.get() != NULL) { std::cout << "ap1 is not empty." << std::endl; } else { std::cout << "ap1 is empty." << std::endl; } if (ap2.get() != NULL) { std::cout << "ap2 is not empty." << std::endl; } else { std::cout << "ap2 is empty." << std::endl; } //测试赋值构造 std::auto_ptr<int> ap3(new int(8)); std::auto_ptr<int> ap4; ap4 = ap3; if (ap3.get() != NULL) { std::cout << "ap3 is not empty." << std::endl; }
智能指针C++中用于管理动态分配的内存的一种机制。它们可以自动地在不再需要释放内存,从而避免内存泄漏和悬挂指针的问题。 shared_ptr是一种引用计数智能指针,它可以跟踪有多少个shared_ptr指向同一个对象,并在没有引用自动释放内存。当创建shared_ptr,它增加引用计数,当销毁或重置shared_ptr,它减少引用计数。只有当引用计数为0,才真正释放内存。\[1\]shared_ptr可以通过构造函数接受一个指向动态分配对象指针来创建,也可以使用std::make_shared函数来创建。\[2\] unique_ptr是一种独占智能指针,它拥有对动态分配对象的唯一所有权。当unique_ptr被销毁,它自动释放内存。unique_ptr不能被复制,但可以通过std::move函数进行转移所有权。\[3\]unique_ptr可以通过构造函数接受一个指向动态分配对象指针来创建。 weak_ptr是一种弱引用智能指针,它指向由shared_ptr管理的对象,但不增加引用计数。weak_ptr可以用于解决shared_ptr的循环引用问题,因为它不导致对象无法释放。\[1\]weak_ptr可以通过shared_ptr的构造函数来创建。 auto_ptrC++11之前的一种智能指针,它类似于unique_ptr,但有一些限制和问题。auto_ptr在复制转移所有权,这可能导致悬挂指针的问题。因此,auto_ptr已经被unique_ptr取代,不推荐使用。 总结来说,shared_ptr是引用计数智能指针,unique_ptr是独占智能指针,weak_ptr是弱引用智能指针,而auto_ptr是已经过的智能指针。它们各自有不同的用途和特点,可以根据具体的需求选择使用。 #### 引用[.reference_title] - *1* *2* *3* [C++11 解决内存泄露问题的智能指针:shared_ptr、unique_ptr、weak_ptr](https://blog.csdn.net/weixin_44120785/article/details/128714630)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十月旧城

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值