C++智能指针——unique_ptr

系列文章目录

C++11新特性大全+实例

文章目录

  • 系列文章目录
  • 前言
  • 一、智能指针是什么?
    • 1.什么是智能指针
    • 2.为什么要使用智能指针
    • 3.智能指针有哪几种
    • 4.智能指针的使用特点
  • 二、unique_ptr
    • 1.构造及简单使用
    • 2.赋值
    • 3.传参
    • 4.基本方法
    • 5.自定义删除器详解
      • 1.为什么要使用自定义的删除器
      • 2.写法
      • 3.实例分析
  • 总结

前言

C++ 这门编程语言的历史可以追溯至 1979 年,当时的 Bjarne Stroustrup(C++ 之父,后续简称 Stroustrup)还在使用 Simula 语言进行开发工作。

1998 年,C++ 标准委员会发布了第一版 C++ 标准,并将其命名为 C++ 98 标准。据不知名人士透露,《带注释的C++参考手册》这本书对 C++ 98 标准的制定产生了很大的影响。

经过作者的不断迭代,一本书往往会先后发布很多个版本,其中每个新版本都是对前一个版本的修正和更新。C++ 编程语言的发展也是如此。截止到目前(2020 年),C++ 的发展历经了以下 3 个个标准:

2011 年,新的 C++ 11 标准诞生,用于取代 C++ 98 标准。

2014 年,C++ 14 标准发布,该标准库对 C++ 11 标准库做了更优的修改和更新;

2017 年底,C++ 17 标准正式颁布;

虽然学习 C++11 需要花些时间,但这是非常值得的;C++11 非常实用,它不但提高了开发效率,还让程序更加健壮和优雅。程序员应该乐于升级换代已有的知识,而学习和使用 C++11 早就是大势所趋。

|版本声明:山河君,未经博主允许,禁止转载

一、智能指针是什么?

1.什么是智能指针

百度词条:智能指针(smart pointer)的一种通用实现技术是使用引用计数(reference count)。智能指针类将一个计数器与类指向的对象相关联,引用计数跟踪该类有多少个对象的指针指向同一对象。

从使用上简单来说:智能指针就是包含重载运算符的类,它能够将将普通的指针封装为一个栈对象并进行追踪。

2.为什么要使用智能指针

程序猿在申请内存时基本都是 new/delete,进行一一对应,手动申请后要进行手动释放。如果忘记释放就会造成内存泄漏。

使用智能指针就是为了避免此类问题的发生,因为智能指针是一个类,在使用时就可以不用关心有没有释放智能指针所指向的内存,因为类对象超出作用域的时候,会自动调用析构函数释放资源。

3.智能指针有哪几种

4种智能指针:auto_ptr, unique_ptr,shared_ptr, weak_ptr 。其中auto_ptr因为在使用场合中会出现一些我们不希望的场景,它存在潜在的内存崩溃问题!目前已弃用,被unique_ptr所替代。

这篇记录是专门讲解unique_ptr智能指针,并会简单和auto_ptr进行对比。

4.智能指针的使用特点

智能指针类重载了解除引用运算符(*)和成员选择运算符(->)。

几乎所有的智能指针都是模板类,包含其功能的泛型实现。

二、unique_ptr

1.构造及简单使用

#include 

using namespace std;

class Test {

public:
	Test()
	{
		strTest = "hello world";
		cout << "this is init" << endl;
	}

	~Test()
	{
		cout << "this is release" << endl;
	}

	void print()
	{
		cout << strTest << endl;
	}

private:
	string strTest;
};

int main()
{
	Test* test1 = new Test();
	unique_ptr<Test> p(test1);
	(*p).print();
}

输出:
C++智能指针——unique_ptr_第1张图片
这里可以看到,虽然我们没有手动释放类对象,但是依旧调用了类对象的析构函数。

2.赋值

unique_ptr持有对象独有权,即保证保证同一时间内只有一个智能指针可以指向该对象。这一点与auto_ptr一样。

(1)例一
首先看一下auto_ptr

#include 

using namespace std;

int main()
{
	auto_ptr<string> q1(new string("123"));
	auto_ptr<string> q2;
	q2 = q1;
	cout << *q2 << endl;
	cout << *q1 << endl;
}

结果:
C++智能指针——unique_ptr_第2张图片
直接出现段错误,这是因为同一时间内只有一个智能指针可以指向该对象。但是auto_ptr可以进行重载“=”进行赋值,这样使用就会导致内存崩溃,也是弃用auto_ptr的原因。

使用unique_ptr则不能进行“=”赋值
在这里插入图片描述
(2)例二
如果想要进行赋值那应该怎么写呢?

unique_ptr<string> q1(new string("123"));
unique_ptr<string> q2;
q2 = move(q1);

(3)例三
还是Test那个例子

int main()
{
	Test* test1 = new Test;
	unique_ptr<Test> p1(test1);
	unique_ptr<Test> p2(test1);
	(*p1).print();
	(*p2).print();
}

结果:可以进行同时访问,但是同一块内存释放了两次,所以尽量不要让unique_ptr指针去维护已经使用new返回值初始化的指针,尽量写成这样unique_ptr q1(new string("123"));
C++智能指针——unique_ptr_第3张图片

3.传参

(1)例一
这种传参不成功跟上文一样,所以如果使用智能指针进行传参,需要使用引用方式,或是使用std::move的方式
C++智能指针——unique_ptr_第4张图片
(2)例二
返回值为智能指针是可以的

unique_ptr<Test> fun2()
{
	Test* test1 = new Test;
	unique_ptr<Test> p1(test1);
	return p1;
}

int main()
{
	unique_ptr<Test> p2 = fun2();
	(*p2).print();
}

结果:为什么这里可以p2 = p1,这里实际上优先move constructor;可以理解为自动调用了move方法。
C++智能指针——unique_ptr_第5张图片

4.基本方法

(1)release
释放其关联的原始指针的所有权,并返回原始指针。
这里的释放并不会摧毁其指向的对象,而是将其指向的对象释放出去。

int main()
{
	Test* test1 = new Test;
	unique_ptr<Test> p1(test1);
	unique_ptr<Test> p2(test1);
	p1.release();
	(*p2).print();
}

结果:此时并没有造成同一块内存释放两次,且没有在release时进行析构
C++智能指针——unique_ptr_第6张图片
(2)reset
释放指向的内存,并且释放了对这块内存的所有权

int main()
{
	string* str1 = new string("123");
	string* str2 = new string("456");
	unique_ptr<string> p1(str1);
	p1.reset(str2);
	cout << *p1 << endl;
}

结果:
在这里插入图片描述
(3)swap
交换两个unique_ptr指针指向区域(交换地址)

int main()
{
	string* str1 = new string("123");
	string* str2 = new string("456");
	unique_ptr<string> p1(str1);
	unique_ptr<string> p2(str2);
	cout << *p1 << endl;
	cout << *p2 << endl;
	p1.swap(p2);
	cout << *p1 << endl;
	cout << *p2 << endl;
}

结果:
C++智能指针——unique_ptr_第7张图片

(4)get
返回unique_ptr维护的指针地址

int main()
{
	unique_ptr<int> ptr(nullptr);
	ptr = make_unique<int>(10);

	cout << *ptr.get() << endl; // 返回10 
}

5.自定义删除器详解

1.为什么要使用自定义的删除器

当对象中又包含到多层申请的内容,不能完全依靠智能指针删除时,例如对象中还包含指针指向一块内存的时候。就需要自定义删除方法了。

2.写法

主要就是自己编写一个删除器,指定输入的参数,然后实现相应的释放操作,并将这个删除器传入 unique_ptr 中。

3.实例分析

(1)步骤1
假设有这么一个的结构体定义如下

// 图像格式定义
typedef struct cv_image_t {
    unsigned char *data;            ///< 指向申请内存
    int width;                      ///< 宽度(以像素为单位)
    int height;                     ///< 高度(以像素为单位)
} cv_image_t;

(2)步骤2
再写一个释放方法

void cv_image_release(cv_image_t* image) {
    if(!image) {
        return;
    }
    delete[] image->data;
    delete image;
    return;
}

(3)步骤3
使用智能指针进行释放

cv_image_t image_input = { 
    (unsigned char*) image,
    image_width,
    image_height,
};

//传入对象,和释放方法
std::unique_ptr<cv_image_t, decltype(cv_image_release)*> image_guard (image_input , cv_image_release);

总结

如果对您有用,不妨点个赞涨涨积分!

你可能感兴趣的:(C++新特性,c++,智能指针)