C++Primer 第十二章
//1.标准库提供了两种智能指针类型来管理动态对象,均定义在头文件memory中,声明在std命名空间。
// shared_ptr:允许多个指针指向同一个对象。
// unique_ptr:独占所指的对象。
// 标准库还定义了weak_ptr的伴随类,它是一种弱作用。指向shared_ptr所管理的对象。 //2.shared_ptr和unique_ptr均支持的操作:
shared_ptr<T> sp
unique_ptr<T> up:空智能指针,指向类型为T的对象
p :将p用作一个判断条件,若p指向一个对象,则为true
*p, p->men :得到p所指向的对象
p.get() :返回p中保存的指针。
swap(p, q)
p.swap(q) :交换p和q的指针 //3.shared_ptr独有的操作:
make_shared<T>(args) :返回一个shared_ptr,指向一个动态分配的类型为T的对象。使用args初始化此对象。是安全的分配和使用动态内存的方法。其本身也是一个模板。
shared_ptr<T> p(q) :p是q的拷贝,此操作会递增q的计数器,q中的指针必须能转为T。
p = q :p和q都是shared_ptr,p的指针必须能指向q所指的对象,此操作会递减p的引用计数,递增q的引用计数。当p的引用计数变为0的时候则释放其管理的内存。
shared_ptr<const int> pInt(new int());
shared_ptr<int> pInt1;
pInt1 = pInt; //错误
pInt = pInt1; //正确
p.unique() :若p的引用计数为1,则返回true,否则返回false
p.use_count() :可能很慢,主要用于调试,返回与p共享对象的智能指针的数量 //4.当在容器中使用了shared_ptr,当不在需要容器中的全部元素的时候,记得用erase删除不再需要的元素。 //5.new和delete:
.在自由空间分配的内存是无名的,因此new无法为其分配的对象命名,而是返回一个指向该对象的指针。
.默认情况下,动态分配的对象是默认初始化的。
.可以采用直接初始化或值初始化的方式,方法是使用()。直接初始化:int *pValue = new int(); 值初始化:int *pValue = new int();
.默认情况下,new失败时候会抛出bad_alloc异常。使用定位new可以避免抛出异常:int *pValue = new (nothrow)int;当分配内存失败的时候,pValue将是一个空指针。nothrow定义在头文件new中,声明在命名空间std中。
.传递给delete的指针必须是动态分配的指针或者是空指针。多次释放相同的指针的行为是未定义的。
.在使用了delete的时候,最好将被操作的指针置空。 //6.可以用new返回的指针来直接初始化shared_ptr,此构造函数是explicit的,所以只能采用直接初始化的方式。 //7.不要用智能指针的get()函数得到的指针去初始化另一个智能指针,否则会导致多次delete同一块内存。
// shared_ptr类的reset成员函数可以将一个新的指针赋予shared_ptr,如果需要的话会释放其原来指向的内存。
// shared_ptr类默认使用delete来充当删除器。可以为shared_ptr对象指定自己的删除器。 //8.智能指针的使用规范:
// A:不使用相同的内置指针初始化或reset多个智能指针
// B:不delete get()返回的指针
// C:不使用get()初始化或reset另一个智能指针
// D:在使用get()返回的指针的时候,要记住当对应的最后一个智能指针销毁后,这个指针就无效了。
// E:在使用shared_ptr的时候,当管理的资源不是new分配的时候,要传递给其一个删除器。 //9.unique_ptr:其有一个可以接受内置指针的构造函数,是explicit的,所以当使用内置指针初始化unique_ptr的时候要采用直接初始化。 //10.unique_ptr的操作:
u = nullptr :将对象置空并释放其资源
u.release() :u放弃对指针的控制权,返回指针并且将u置空
u.reset() :释放u指向的对象,并将u置空
u.reset(q) :释放u指向的对象,并将u指向内置指针q
u.reset(nullptr):释放u指向的对象,并将u置空
// 虽然不能拷贝或赋值unique_ptr,但是可以通过release和reset来将指针的控制权由一个unique(非const)转移到另一个unique: p.reset(p1.release()); //11.不能拷贝或赋值unique_ptr的规则有一个例外:可以拷贝或赋值一个将要被销毁的unique_ptr:比如从函数返回一个unique_ptr,返回局部unique_ptr对象。
unique_ptr<int> fun() {unique_ptr<int> p(new int()); return p;}
unique_ptr<int> p = fun();//p = unique_ptr 10 //12.weak_ptr是一种不控制指向对象生存期的智能指针,它指向一个由shared_ptr管理的对象。将一个weak_ptr绑定到一个shared_ptr上不会影响后者的使用计数。
w = p :p可以是一个shared_ptr对象或者是weak_ptr对象。赋值后w将共享p的对象
w.reset() :将w置空
w.use_count():与w共享对象的shared_ptr的数量
w.expired() :若w.use_count()为0,则返回true,否则返回false expire[ex·pire || ɪk'spaɪə]v.期满,断气,
w.lock() :如果w.expired()为true,返回一个空的shared_ptr,否则返回一个指向w的对象的shared_ptr。
// 由于对象可能不存在,所以weak_ptr不能直接访问对象,而要通过lock()函数。 //13.分配动态数组内存的时候,分配的大小为0也是允许的,但是不能对此指针进行解引用(vs2010下可以对其解引用,但是最好别用)。对于动态数组不能应用begin()和end()。要搭配使用delete[]。
// delete[]是按照逆序释放内存的。分配动态数组的时候可以使用值初始化,但是不能给出初始化器(这个特性导致无法使用new[]来为没有默认构造函数的类型分配动态数组)。int *p = new int[10]();是可以的。int *p = new int[10](0);是不可以的。 //14.使用unique_ptr可以管理一个动态数组,必须在类型后跟一对尖括号:unique_ptr<int []> pInt(new int[10]());在销毁pInt的时候,会自动使用delete[];
// 与unique_ptr不同,shared_ptr不直接支持管理动态数组。如果希望使用shared_ptr管理动态数组,必须提供自定义的删除器。shared_ptr<int> pInt(new int[10](), [](int *p){delete []p;});
// unique_ptr支持直接管理动态数组,其提供了下标运算符。对应的,shared_ptr不支持直接管理动态数组,其不支持下标运算符,只能通过其get()函数得到对象的指针,通过指针偏移的方式去访问动态数组中的对象。 //15.当分配一大块内存的时候,我们通常计划在这块内存上按需构造对象。在此情况下,我们希望将内存分配和对象构造分离,这意味着我们可以分配大块内存,但是只在真正需要时才真正执行对象创建操作。
// 标准库allocator类定义在头文件memory中,声明在命名空间std中。它可以将内存分配和对象构造分离开来。其本身是一个类模板,会根据给定的对象类型来确定恰当的内存大小和对齐位置。
class CTest
{
public:
CTest(int i) : value(i){}
public:
int value;
};
allocator<CTest> allocTest;
CTest *p = allocTest.allocate(); //分配一段原始的未经构造的内存。指针p所指向40字节的内存是未经构造的
int value = p[].value; //value = -842150451。还未构造对象的情况下使用原始内存是错误的,虽然vs2010不报错,但是也不要这样做。
allocTest.construct(p, CTest()); //构造第一个对象,调用对象的构造函数
allocTest.destroy(p); //调用对象的析构函数,一旦元素被销毁,就可以在这块内存上保存其他的指定对象。
allocTest.deallocate(p, ); //释放从p开始的内存,从p开始的位置保存了10个CTest类型的对象。这个10是之前调用allocate时指定的。在调用此函数前,必须对此内存块中已经构造的对象调用destroy(); //16.uninitialized_copy(beg1, end1, beg2)
// uninitialized_copy_n(beg1, n, beg2):从输入迭代器指定的范围拷贝元素到迭代器beg2指定的未构造的原始内存中。此函数返回值为beg2中最后一个被构造的元素的尾后迭代器。
// uninitialized_fill(beg1, end1, t)
// uninitialized_fill_n(beg1, n, t):在由前两个参数指定的序列中,创建对应数目的对象,并用t来进行初始化。
allocator<CTest> allocTest;
CTest *pTest = allocTest.allocate();
vector<CTest> vecTest;
for(int i = ; i < ; ++i) {vecTest.emplace_back(i);}
auto pTem = uninitialized_copy(vecTest.begin(), vecTest.end(), pTest);
uninitialized_fill(pTem, pTem + , );
//pTest指向的内存中对象的值:0到9,10个1 allocator<unique_ptr<int>> allocTest;
auto *pTest = allocTest.allocate();
uninitialized_fill(pTest, pTest + , new int());
int sum = ;
for(int i = ; i < ; ++i){sum += *(pTest[i]);} //sum = 20; //17
void Fun0(CRITICAL_SECTION* p)
{
LeaveCriticalSection(p);
}
auto FunTest = [](CRITICAL_SECTION* p){LeaveCriticalSection(p);};
CRITICAL_SECTION Cs;
shared_ptr<CRITICAL_SECTION> pShareCs(&Cs, [](CRITICAL_SECTION* p){LeaveCriticalSection(p);});
unique_ptr<CRITICAL_SECTION, decltype(Fun0)*> pUniqueCs0(&Cs, Fun0);
unique_ptr<CRITICAL_SECTION, decltype(FunTest)> pUniqueCs1(&Cs, FunTest);
//unique_ptr<CRITICAL_SECTION, decltype([](CRITICAL_SECTION* p){LeaveCriticalSection(p);})> pUniqueCs2(&Cs, [](CRITICAL_SECTI ON* p){LeaveCriticalSection(p);});
//error C3477: lambda 不能出现在未计算的上下文中
//unique_ptr<CRITICAL_SECTION> pUniqueCs3(&Cs, Fun1);
//error C2664: “std::unique_ptr<_Ty>::unique_ptr(_RTL_CRITICAL_SECTION *,const std::default_delete<_Ty> &)”: 不能将参数 2 从“`an onymous-namespace'::<lambda0>”转换为“const std::default_delete<_Ty> &”
C++Primer 第十二章的更多相关文章
- C++ Primer : 第十二章 : 文本查询程序
C++ Primer书上这个例子讲的很不错,写写帮助自己理解标准库和智能指针. .h 文件内容 #include <fstream> #include <iostream> # ...
- C++ Primer : 第十二章 : 动态内存之unique_ptr和weak_ptr
unique_ptr 一个unique_ptr拥有它所管理的对象,与shared_ptr不同,unique_ptr指向的对象只能有一个用户.当unique_ptr被销毁后,它所指向的对象也被销毁. 定 ...
- C++ Primer : 第十二章 : 动态内存之allocator类
标准库allocator类定义在头文件 <memory>中.它帮助我们将内存分配和构造分离开来,它分配的内存是原始的.未构造的. 类似vector,allocator也是一个模板类,我们在 ...
- C++ Primer : 第十二章 : 动态内存之动态数组
动态数组的分配和释放 new和数组 C++语言和标准库提供了一次分配一个对象数组的方法,定义了另一种new表达式语法.我们需要在类型名后跟一对方括号,在其中指明要分配的对象的数目. int* arr ...
- C++ Primer : 第十二章 : 动态内存之shared_ptr与new的结合使用、智能指针异常
shared_ptr和new结合使用 一个shared_ptr默认初始化为一个空指针.我们也可以使用new返回的指针来初始化一个shared_ptr: shared_ptr<double> ...
- C++ Primer : 第十二章 : 动态内存之动态内存管理(new和delete)
C++语言定义了两个运算符来分配和释放动态内存:运算符new分配内存,运算符delete释放new分配的内存. 运算符new和delete 使用new动态分配和初始化对象 在自由空间分配的内存是无名的 ...
- C++ Primer : 第十二章 : 动态内存之shared_ptr类实例:StrBlob类
StrBlob是一个管理string的类,借助标准库容器vector,以及动态内存管理类shared_ptr,我们将vector保存在动态内存里,这样就能在多个对象之间共享内存. 定义StrBlob类 ...
- C++ Primer : 第十二章 : 动态内存之shared_ptr类
在C++中,动态内存是的管理是通过一对运算符来完成的:new ,在动态内存中为对象分配空间并返回一个指向该对象的指针,delete接受一个动态对象的指针,销毁该对象,并释放该对象关联的内存. 动态内 ...
- C++ Primer之 十二章 类
1.关于类的const对象 const对象只能调用声明为const的成员函数,在这篇csdn博客中也讨论了这个问题. 究其原因是因为 const 对象A 调用了非const函数F, F因为没有cons ...
随机推荐
- Solr 连接数据库
实际工程应用中,从数据库导出数据创建索引再常见不过了,现在实验一下从数据库导入数据创建索引. 一.版本说明 Solr版本:4.7.0 数据库:sqlserver2005 二.配置步骤 1. 准备的j ...
- word size
Computer Systems A Programmer's Perspective Second Edition Running throughout the system is a collec ...
- Flink DataSet API Programming Guide
https://ci.apache.org/projects/flink/flink-docs-release-0.10/apis/programming_guide.html Example ...
- Finally 与 return
网上有很多人探讨Java中异常捕获机制try...catch...finally块中的finally语句是不是一定会被执行?很多人都说不是,当然他们的回答是正确的,经过我试验,至少有两种情况下fina ...
- Ubuntu/Deepin下常用软件汇总(持续更新)
最近开始用Ubuntu了,好多软件都不是常用的了,在这边留底,以免忘记.如果没有写安装方法,则直接在软件源中可以找到 UNetbootin U盘制作工具,制作Ubuntu的安装U盘超好用 Braser ...
- Android轻量缓存框架--ASimpleCache
[转] 大神真面目 稀土掘金,这是一个针对技术开发者的一个应用,你可以在掘金上获取最新最优质的技术干货,不仅仅是Android知识.前端.后端以至于产品和设计都有涉猎,想成为全栈工程师的朋友不要错过! ...
- style="display"之后不能获取offsetHeight或clientWidth这类测量的值
如果在html元素中设置了style="display:none;height:90px;"的属性后,是无法获得offsetLeft ,offsetWidth,offsetTop, ...
- 371. Sum of Two Integers
不用加减法计算两个整数的和.这道题其实是考察一些基本的布尔代数知识.我们知道,二进制表示时: 0 + 0 = 00 1 + 0 = 01 0 + 1 = 01 1 + 1 = 10 所以,两个二进制整 ...
- [LeetCode]题解(python):083 - Remove Duplicates from Sorted List
题目来源 https://leetcode.com/problems/remove-duplicates-from-sorted-list/ Given a sorted linked list, d ...
- emmc boot1 boot2 partition
使用mfg tool烧写android5.1的镜像之后,再使用旧版的mfg tool烧写linux或者android镜像,都不能正常启动,而且运行的uboot还是android5.1版本的uboot. ...