智能指针用法

在C++中, 有4种常用的智能指针: auto_ptr、unique_ptr、shared_ptr以及weak_ptr.

  智能指针的作用是管理一个指针,因为存在以下这种情况:申请的空间在函数结束时忘记释放,造成内存泄漏。所以智能指针的作用原理就是在函数结束时自动释放内存空间,不需要手动释放内存空间。

auto_ptr

auto_ptr在C++17 中已经被废除啦,所以在是不建议使用的。 auto_ptr 是通过由 new 表达式获得的对象,并在 auto_ptr 自身被销毁时删除该对象的智能指针。它可用于为动态分配的对象提供异常安全、传递动态分配对象的所有权给函数和从函数返回动态分配的对象。
复制 auto_ptr ,会复制指针并转移所有权给目标: auto_ptr 的复制构造和复制赋值都会修改其右侧参数,而且“副本”不等于原值。因为这些不常见的复制语义,不可将 auto_ptr 置于标准容器中。此用途及其他使用更适合用 std::unique_ptr 。

unique_ptr

template<
    class T,
    class Deleter = std::default_delete<T>
> class unique_ptr;
template <
    class T,
    class Deleter
> class unique_ptr<T[], Deleter>;

unique_ptr有独享资源的语义,意味着一个指向资源的指针, 只能有一个unique_ptr指向该资源, 不能有两个或者多个unique_ptr指向给资源, 也就是说unique_ptr不能有赋值或者copy 赋值。 那么, 如果一定要 从一个智能指针赋值给另外一个智能指针, 可以通过std::move 将源指针转换为一个右值, 然后通过指针的转移来进行赋值。

unique_ptr<int> ap(new int(100);
unique_ptr<int> one(ap) ; // copy构造函数会出错
unique_ptr<int> two = one; //copy 赋值函数会出错

//这里是显式的所有权转移. 把up所指的内存转给uPtr2了,而up不再拥有该内存.
unique_ptr<int> uPtr2 = std:move(ap) ; 

auto_ptr 与unique_ptr的区别:
unique_ptr和auto_ptr真的非常类似.其实你可以这样简单的理解:
auto_ptr是可以随便赋值,但赋值完了之后原来的对象就不知不觉的报废.搞得人莫名其妙;另外auto_ptr不能被放进容器里面;
unique_ptr就干脆不让你可以随便去复制、赋值,如果实在想传个值,就显式的说明内存转移std:move一下,然后这样传值完了之后,之前的对象也同样报废了,只不过整个std::move你让明显的知道这样操作后会导致之前的unique_ptr对象失效。
unique_ptr也同样不能直接做为容器元素,但可以通过std::move的方式来放入容器;
另外, unique_ptr还可以至指定deleter, 可以指定相关resource如何被删除, 这一点是auto_ptr所不具备的。

shared_ptr

共享指针:是指由几个关联的共享指针共享一块内存,用use_count(引用计数)来表示有几个共享指针使用这块内存,只有当所有共享指针都不指向这块内存后,引用计数变0,这块内存才会被自动释放。

shared_ptr的使用要点:
- 不要用一个原始指针初始化多个shared_ptr,原因在于,会造成二次销毁;
- 不要在函数实参中创建shared_ptr。因为C++的函数参数的计算顺序在不同的编译器下是不同的。正确的做法是先创建好,然后再传入;
- 禁止通过shared_from_this()返回this指针,这样做可能也会造成二次析构;
- 避免循环引用。智能指针最大的一个陷阱是循环引用,循环引用会导致内存泄漏。解决方法是AStruct或BStruct改为weak_ptr;

shared_ptr<int> sp(new int(1));
shared_ptr<int> sp2 = sp;  //ok
shared_ptr<int> sp3(new int(2));

sp->ptr = sp3;    // sp and sp3循环引用
sp3->ptr = sp;  

weak_ptr

弱指针:同时标准库还定义了弱指针(weak_ptr),之所以称作弱指针是因为它并不控制所指内存的生存期,这一点与裸指针十分相似,但弱指针上定义了w.use_count、w.lock()等方法让我们在使用弱指针之前就知道所指内存有没有被释放,只有在内存没有被释放的时候我们才使用它,避免了访问空悬指针错误。

右值引用

在使用智能指针或者新的C++1X的新特性的时候, 经常会用到右值引用, 它是一个非常重要的概念。
在C++中, 左值是指有名字并且分配了内存空闲的变量, 与之相反的就是友值。 比如:

int num_a = 1;
int& num_b = num_a;

这里的num_a是某一个int型变量, 它的名字是num_a, 地址是&num_a;
在等号右边的1, 是一个友值, 因为他没有自己的名字和地址, 只知道它的值是1;
要实现一个左值引用, 可以使用num_b的方式。

右值引用是为了解决在C++中昂贵的对象复制以及模板对象的复制来实现队形所有权的转移。 要是用右值引用需要定义对象的右值的构造函数和复制函数, 它们有时候也被成为移动构造函数、移动复制函数。

A& operator=(const A&& r)
A(const A&& r)

void func(const A&&);

比如, 上例中func函数需要传入一个右值函数, 通常我们定义的变量都是左值的, 如何将左值转化为右值哪?
我们可以调用std::move来实现。

template< class T >                                                 (C++11 起)
typename std::remove_reference<T>::type&& move( T&& t ) noexcept;   (C++14 前)


template< class T >                                                 (C++14 起)
constexpr typename std::remove_reference<T>::type&& move( T&& t ) noexcept;

猜你喜欢

转载自blog.csdn.net/baijiwei/article/details/80866048
今日推荐