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

本文介绍了C++98中的智能指针auto_ptr,包括其使用方式、存在的问题以及在C++11标准中被废弃的原因。主要问题包括:多次析构导致的内存异常、赋值操作后的所有权转移以及与函数参数传递和容器使用的不兼容。C++11引入的unique_ptr作为替代,增强了安全性并支持了数组。
摘要由CSDN通过智能技术生成

有了前面的基础,我们来看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;
}

![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/782665bdd8d957ff99339ff4f674bc51.png) T* release();realease() 将 auto_ptr 封装在内部的指针置为 nullptr, 但并不会破坏指针所指向的内容, 函数返回的是内部指针置空之前的值;

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

可以调用reset()来重新分配指针的所有权,reset中会先释放原来的内部指针的内存,然后分配新的内部指针。
在这里插入图片描述
void reset (T* ptr = nullptr);直接释放封装的内部指针所指向的内存, 如果指定了 ptr 的值, 则将内部指针初始化为该值(否则将其设置为nullptr)

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的使用及废除原因学习笔记

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

十月旧城

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

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

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

打赏作者

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

抵扣说明:

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

余额充值