1.新的标准库提供了两种智能指针类型,shared_ptr允许多个指针指向同一个对象,unique_ptr则独占所指的对象。标准库还定义了一个名为weak_ptr的伴随类,它是一种弱引用,指向shared_ptr所管理的对象。

2.智能指针也是模板,默认初始化的智能指针中保存着一个空指针。

3.智能指针的操作:

4.make_shared用参数来构造指定类型的对象。

std::shared_ptr<int> p = std::make_shared<int>(42);    // 指向一个值为42的int型shared_ptr
std::shared_ptr<std::string> p1 = std::make_shared<std::string>(2,'1'); // 指向一个值为"11"的string类型shared_ptr
std::shared_ptr<int> p2 = std::make_shared<int>(); // 值初始化为0

5.我们可以认为每个shared_ptr有一个引用计数,无论何时我们拷贝一个shared_ptr,计数器都会递增,当我们给shared_ptr赋予一个新值或是shared_ptr被销毁时,计数器就会递减。

6.当指向一个对象的最后一个shared_ptr被销毁时,shared_ptr类会自动销毁此对象。它是通过析构函数完成销毁工作的。所占用的内存也会被释放。

7.shared_ptr在无用之后仍然保留的一种可能情况是,你将shared_ptr放在一个容器中(其实已经做了拷贝),随后重排了容器,从而不再需要某些元素,而只使用其中一部分,所以要记得用erase删除不再需要的那些元素。

8.在自由空间分配的内存是无名的,因此new无法为其分配的对象命名,而是返回一个指向该对象的指针。

9.默认情况下,动态分配的对象是默认初始化的。这意味着内置类型或组合类型的值将是为定义的,而类类型的对象将用默认构造函数进行初始化。也可以对动态分配的内存进行值初始化,只需在类型名之后跟一对空括号即可。

int *p = new int;    // 默认初始化,*p的值未定义
int *p1 = new int(); // 值初始化为0,*p1为0

10.当我们提供一个括号包围的初始化器,就可以使用auto从此初始化器来推断我们想要分配的对象的类型,但是正因如此,只有当括号中仅有单一初始化器时才可以使用auto。

int a, b;
int i = ;
auto p = new auto(i); // p指向一个值为1的int型,但不是指向i
auto p1 = new auto{a,b}; // 错误,括号中只能有单个初始化器

11.定位new表达式允许我们向new传递额外的参数。

int *p = new int;    // 如果分配失败,new抛出std::bad_alloc
int *p1 = new (std::nothrow) int; // 如果分配失败,new返回一个空指针

12.我们传递给idelete的指针必须指向动态分配的内存,或者是一个空指针。释放一块并非new分配的内存,或者将相同的指针值释放多次,其行为是未定义的。

13.我们可以用new返回的指针来初始化智能指针,接受指针参数的智能指针构造函数是explicit的,因此不能将一个内置指针隐式转换为一个只能指针,必须使用直接初始化形式来初始化一个智能指针。

std::shared_ptr<int> p = new int();     // 错误,必须使用直接初始化形式
std::shared_ptr<int> p1(new int()); // 正确,使用了直接初始化形式

14.默认情况下,一个用来初始化智能指针的普通指针必须指向动态内存,因为智能指针默认使用delete释放它所关联的对象,我们可以将智能指针绑定到一个指向其他类型的资源的指针上,但是为了这样做,必须提供自己的操作来代替delete。

15.定义和改变shared_ptr的其他方法:

16.使用一个内置指针来访问一个智能指针所负责的对象是很危险的,因为我们无法知道对象何时会被销毁。

void test(std::shared_ptr<int> p)
{
// ...
} int *p = new int(); // p是一个普通指针,不是一个智能指针
test(p); // 错误,不能将int*转换为一个shared_ptr<int>
test(std::shared_ptr<int>(p)); // 合法的,但是一旦函数调用结束,p指向的内存就被释放了
int j = *p; // 未定义的,p是一个空悬指针

17.get用来将指针的访问权限传递给代码,你只有在确定代码不会delete指针的情况下,才能使用get。特别的,永远不要用get初始化另一个智能指针或者为另一个智能指针赋值。

std::shared_ptr<int> p(new int());    // p的引用计数为1
int *q = p.get(); // 正确,但是注意不要让q被释放
if ()
{
std::shared_ptr<int> p1(q);
} // 程序块结束,p1被销毁,所指的内存被释放
int i = *p; //未定义,p所指的内存被释放了

18.与赋值类似,reset会更新引用计数,如果需要的话,会释放p指向的对象。reset经常与unique一起使用。

std::shared_ptr<int> p(new int());
// ...
if (!p.unique())
p.reset(new int()); // 我们不是唯一用户,分配新的拷贝
else
(*p)++; // 我们是唯一用户,可以直接改变对象的值

19.如果在new和delete之间发生异常,且异常未被捕获,则内存就永远不会被释放,使用智能指针就可以避免这个问题。

20.当一个shared_pt(unique_ptr也一样)r被销毁时,默认会对它管理的指针进行delete操作,我们可以自己定义一个删除器函数来代替delete操作。

class test
{
public:
~test() {};
}; void my_delete(test *t)
{
t->~test();
} std::shared_ptr<test> p(new test(), my_delete); // p被销毁时会调用my_delete

21.unique_ptr也必须采用直接初始化的形式,而且unique_ptr不支持普通的拷贝或赋值操作,但是有如下操作。

  • 如果release返回的指针没有被其他的指针保存,则不仅内存没有被释放,而且我们丢失了指针

22.不能拷贝unique_ptr的规则有一个例外,我们可以拷贝或赋值一个将要被销毁的unique_ptr。

std::unique_ptr<int> clone(int i)
{
return std::unique_ptr<int>(new int(i));
}
// or
std::unique_ptr<int> clone1(int i)
{
std::unique_ptr<int> ret(new int(i));
return ret;
}

23.weak_ptr是一种不控制所指向对象生存期的智能指针,它指向一个shared_ptr管理的对象。所以weak_ptr不会改变shared_ptr的引用计数。

24.weak_ptr定义了如下操作:

25.由于对象可能不存在,我们不能使用weak_ptr直接访问对象,而必须调用lock.

std::shared_ptr<int> p(new int());
std::weak_ptr<int> p1(p); if (std::shared_ptr<int> np = p1.lock()) // 如果np为空则不可操作
{
(*np)++;
}

C++ Primer 笔记——智能指针的更多相关文章

  1. c++学习笔记——智能指针

    智能指针是为了便于管理动态内存,能够自动管理释放所指向的对象. 智能指针共有三种:1.shared_ptr允许多个指针指向同一个对象:2.unique_ptr独占所指向的对象:3.weak_ptr是一 ...

  2. C++智能指针初学小结

    本篇随笔仅作为个人学习<C++ Primer>智能指针一节后的部分小结,抄书严重,伴随个人理解.主要介绍shared_ptr.make_shared.weak_ptr的用法和联系. C++ ...

  3. C++中的智能指针、轻量级指针、强弱指针学习笔记

    一.智能指针学习总结 1.一个非const引用无法指向一个临时变量,但是const引用是可以的! 2.C++中的delete和C中的free()类似,delete NULL不会报"doubl ...

  4. C++笔记(11) 智能指针

    1. 设计思想 智能指针是行为类似于指针的类对象,但这种对象还有其他功能.首先,看下面的函数: void remodel(std::string & str) { std::string * ...

  5. C++的智能指针学习笔记(初)

    C++ primer plus 16.2节介绍了auto_ptr,该模板类在C++11中已弃用,目前已被shared_ptr代替. auto_ptr又叫做智能指针,用于管理动态内存分配的用法. 为什么 ...

  6. EC笔记:第三部分:17、使用独立的语句将newed对象放入智能指针

    一般的智能指针都是通过一个普通指针来初始化,所以很容易写出以下的代码: #include <iostream> using namespace std; int func1(){ //返回 ...

  7. C++11智能指针读书笔记;

    智能指针是一个类对象,而非一个指针对象. 原始指针:通过new建立的*指针 智能指针:通过智能指针关键字(unique_ptr, shared_ptr ,weak_ptr)建立的指针 它的一种通用实现 ...

  8. C++ Primer : 第十二章 : 动态内存之shared_ptr与new的结合使用、智能指针异常

    shared_ptr和new结合使用 一个shared_ptr默认初始化为一个空指针.我们也可以使用new返回的指针来初始化一个shared_ptr: shared_ptr<double> ...

  9. osg(OpenSceneGraph)学习笔记1:智能指针osg::ref_ptr<>

    OSG的智能指针,osg::ref_ptr<> osg::Referenced类管理引用计数内存块,osg::ref_ptr需要使用以它为基类的其它类作为模板参数. osg::ref_pt ...

随机推荐

  1. Hibernate学习(三)

    Hibernate的查询方法(五种) 一.OID查询:按主键查询 --get( ) --load( ) 二.对象导航查询:通过已经查询到的联系人,得到起关联的对象 三.SQL查询 四.HQL查询(** ...

  2. Oracle根据【日期】组,其他条件根据PIVOT行转列。使每个日期条件关联的其他数据只有一行。

    select OPER_TIME, MICROPAY, REFUND from ( select trunc(oper_time) oper_time, class_name, sum(total_f ...

  3. BurpSuite使用笔记

    参考:Burp Suite 实战指南 Proxy模块 options--> add 设置监听地址,端口 binding 如果是作为本地浏览器代理默认(127.0.0.1:8080)就可以了. 如 ...

  4. ifconfig相关参数及用法说明

    一.ifconfig ifconfig 主要是可以手动启动.观察与修改网络接口的相关参数,可以修改的参数很多,包括 IP 参数以及 MTU 等都可以修改,它的语法如下: [root@linux ~]# ...

  5. android studio定时器

    1.超时 CountDownTimer第一个参数超时时间,第二个参数多久执行一次onTick(), 到达设定的超时时间执行onFinsh(),cancel取消超时计数,start重新开始(从零开始). ...

  6. Mybatis--02

    主要内容: 1 输入映射和输出映射 输入参数映射 返回值映射 2 动态sql if where foreach sql片段 3 关联查询 一对一关联 一对多关联 4 整合Spring #{}代表一个占 ...

  7. C/C++中容易造成内存溢出的函数

    1.strcpy() strcpy()函数将源字符串复制到缓冲区.没有指定要复制字符的具体数目.复制字符的数目直接取决于源字符串中的数目.如果源字符串碰巧来自用户输入,且没有专门限制其大小,则有可能会 ...

  8. Python-递归、三元表达式列表生成式等

    一.函数递归 1.什么是函数递归:函数的递归调用是函数嵌套的一种特殊形式,在调用一个函数的过程中又直接或者间接地调用该函数本身,称之为函数的递归调用 2.递归调用必须明确的两个阶段: 1.回溯:一次次 ...

  9. 关于STM32 __IO 的变量定义

    这个_IO 是指静态 这个 _IO 是指静态 volatile uint32_t 是指32位的无符号整形变量uint32_t 是指32位的无符号整形变量: 搞stm32这么久了,经常看到stm32里面 ...

  10. c# 操作Word总结(车)

    在医疗管理系统中为保存患者的体检和治疗记录,方便以后的医生或其他人查看.当把数据保存到数据库中,需要新建很多的字段,而且操作很繁琐,于是想到网页的信息创建到一个word文本中,在显示的时,可以在线打开 ...