#include <iostream>
#include <vector>
#include <string>
#include <list>
#include <memory> //智能指针类
using namespace std;
/*
智能指针:新标准提供了两种智能指针
①shared_ptr: 允许多个指针指向同一个对象
②unique_ptr: “独占”所指向的对象
此外,新标准还定义了一个名为weak_ptr的伴随类,它是一种弱引用,指向shared_ptr所管理的对象。这三种类型都定义在memory头文件中。
*/
int main()
{
//shared_ptr:类似vector,智能指针也是模板,当我们创建一个智能指针时,必须提供额外的信息-指针可以指向的类型。
//shared_ptr<int> p1; //可以指向int的shared_ptr,初始值为null
//shared_ptr<list<string>>; //可以指向string的list的智能指针
//注意:默认初始化的智能指针中保存着一个空指针。智能指针的使用方式与普通指针类似
//make_shared函数:最安全的分配和使用动态内存的方法是调用一个名为make_shared 的标准库函数。此函数在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr.
//指向值为42的int对象的shared_ptr
shared_ptr<int> p1 = make_shared<int>(42);
cout << *p1 << endl;
//指向一个值为‘9999999999’的string对象的shared_ptr
shared_ptr<string> p2 = make_shared<string>(10, '9');
cout << *p2 << endl;
//指向一个值初始化的int对象的shared_ptr
//值初始化:对于内置类型比如int,元素初始值会自动设为0.如果元素是某种类类型比如string,则元素由类默认初始化.
shared_ptr<int> p3 = make_shared<int>();
cout << *p3 << endl;
/*
shared_ptr的拷贝和赋值
shared_ptr允许多个指针指向同一个对象,当进行拷贝或赋值操作时,每个shared_ptr 都会记录有多少个其他shared_ptr指向相同的对象。我们可以认为每个shared_ptr都有一个关联的计数器,通常称其为引用计数(reference count)
计数器递增的情况:
①用一个shared_ptr初始化另一个shared_ptr
②将它作为参数传递给一个函数(指针形参)
③作为函数的返回值
计数器递减的情况:
①给shared_ptr赋予一个新值
②shared_ptr被销毁(例一个局部shared_ptr变量离开其作用域)
一旦一个shared_ptr的计数器变为0,它就会自动释放自己所管理的对象。
*/
cout << endl;
cout << "---------------------------\n";
shared_ptr<int> p4 = make_shared<int>(1024);
if (p4.unique())
{
//unique() 函数:若p4.use_count() 为1,返回true,否则返回false
//use_count():返回与p共享对象的智能指针数量:可能很慢,主要用于调试
cout << "只有p4指向共享内存对象-1024\n";
cout << "指向共享内存1024的智能指针数量: " << p4.use_count() << endl;
}
shared_ptr<int> p5 = p4; //以p4初始化p5,递增p4指向的对象的引用计数
cout << "是否只有一个智能指针指向共享内存: " << p5.unique() << endl;
cout << "p4调用-指向共享内存1024的智能指针数量: " << p4.use_count() << endl;
cout << "p5调用-指向共享内存1024的智能指针数量: " << p5.use_count() << endl;
cout << endl;
cout << "---------------------------\n";
{
//一个新的作用域
cout << "-------新作用域--------\n";
shared_ptr<int> p6(p4); //以p4 初始化p6,引用计数加一
cout << "新作用域内p6调用-共享对象: " << *p6 << endl;
cout << "新作用域内p6调用-指向共享内存1024的智能指针数量: " << p6.use_count() << endl;
}//离开该作用域后p6被销毁,但由于还有智能指针指向共享内存,所有共享内存资源不会释放
cout << endl;
cout << "---------------------------\n";
cout << "p4调用-共享对象: " << *p4 << endl;
cout << "p5调用-共享对象: " << *p5 << endl;
cout << "p4调用-指向共享内存1024的智能指针数量: " << p4.use_count() << endl;
cout << "p5调用-指向共享内存1024的智能指针数量: " << p5.use_count() << endl;
cout << endl;
cout << "---------------------------\n";
//shared_ptr 和 new 结合使用
//前述:如果我们不初始化一个智能指针,它就会被初始化为一个空指针。例
//shared_ptr<int> p7;
//cout << p7 << endl;
//我们还可以用new 返回的指针初始化智能指针
//注意:接受指针参数的智能指针构造函数是explicit的(无法进行隐式类型转换,只能直接初始化),因此我们不能将一个内置指针隐式转换成智能指针,必须使用直接初始化形式。例:
//shared_ptr<int> p9 = new int(1025); //编译器报错
shared_ptr<int> p8(new int(666));
cout << "p8调用-共享对象: " << *p8 << " 指向共享内存的智能指针数量: " << p8.use_count() << endl;
cout << endl;
cout << "---------------------------\n";
//get() 函数:智能指针类型定义了一个名为get的函数,它返回一个内置指针,指向智能指针管理的对象。
//设定情况:向不能使用智能指针的代码传递一个内置指针,使用get返回的指针的代码不能delete此指针。
auto p9 = p8.get();
cout << "p9指向的共享内存对象: " << *p9 << endl;
cout << "使用get返回指针并没有增加p8的引用计数: " << p8.use_count() << endl;
cout << endl;
cout << "---------------------------\n";
//reset()函数
//①p.reset(): 若p是唯一指向唯一指向其管理的共享内存对象的shared_ptr, reset会释放此对象
//②p.reset(q): 若传递了可选的内置指针q, 会令p 指向q, 否则p置空
//③p.reset(q, d): 若传递了可调用参数d,将会调用d 而不是delete 来释放q
//通常reset 和 unique 来控制多个shared_ptr 共享的对象
//例:释放p8 管理的共享对象内存
p8.reset();
cout << "p8调用-指向共享内存的智能指针数量: " << p8.use_count() << endl;
//同时将指向该内存的内置指针置空,否则内置指针p9就会变成空悬指针(指向一块曾经保存数据对象但现在已经无效的内存的指针)
p9 = nullptr;
cout << endl;
cout << "---------------------------\n";
p5.reset(); //释放p5,因为还有p4指向共享内存,所有内存不会释放。引用计数减一
cout << "p4调用-共享对象: " << *p4 << endl;
cout << "p4调用-指向共享内存1024的智能指针数量: " << p4.use_count() << endl;
cout << endl;
cout << "---------------------------\n";
p4.reset(new int(555)); //释放p4指向的共享内存,同时使p4指向新的内存
cout << "p4调用-共享对象: " << *p4 << endl;
cout << "p4调用-指向共享内存1024的智能指针数量: " << p4.use_count() << endl;
cout << "p5调用-指向共享内存1024的智能指针数量: " << p5.use_count() << endl;
cout << endl;
cout << "---------------------------\n";
//unique_ptr : 一个unique_ptr "拥有"它所指向的对象
//与shared_ptr 不同,某个时刻只能有一个unique_ptr 指向一个给定对象,当unique_ptr被销毁时,它所指向的对象也被销毁
//初始化:与shared_ptr不同,没有类似make_shared的标志库函数返回一个unique_ptr, 当我们定义一个unique_ptr时,需要将其绑定到一个new 返回的指针上。
//注意:同shared_ptr的接受指针参数的构造函数一样,unique_ptr的带参构造也是explicit的,只能采用直接初始化.
unique_ptr<int> up1; //一个空的unique_ptr
unique_ptr<int> up2(new int(1024)); //指向一个值为1024的int对象的unique_ptr
cout << "up2调用-独占对象: " << *up2 << endl;
//unique_ptr<int> up3(up2); //错误,不支持拷贝
//unique_ptr<int> up4 = up2; //错误,不支持赋值
cout << endl;
cout << "---------------------------\n";
//typedef vector<string>::size_type size_type;?
//转移控制权
//①p.release() : 放弃对独占对象的控制权,返回指向该内存对象的指针,并将p置空
//②p.reset(): 释放调用p指向的对象内存
//③p.reset(q) : 如果提供了内置指针q(必须是动态分配的内存), 则令p指向这个对象,否则将p置空(即没有q参数)
//tips: release返回的指针通常被用来初始化另一个智能指针或给另一个智能指针赋值
//up2.release(); //危险操作:up2放弃了对int对象的控制权,并将up2置空,但这里没有用内置指针变量接受其返回的指向int对象的指针。即up2没有释放int对象内存,且丢失了指向该对象的指针!!!
//正确用法
auto q = up2.release(); //但记得手动delete q, 释放内存
delete q;
cout << endl;
cout << "---------------------------\n";
//向unique_ptr传递删除器
//注意:unique_ptr管理删除器的方式与shared_ptr不同。因为重载一个unique_ptr中的删除器会影响到unique_ptr类型以及如何构造(reset)该类型对象。
//步骤:在尖括号中unique_ptr指向类型之后提供删除器类型,在创建或reset一个这种unique_ptr类型对象时,必须提供一个指向类型的可调用对象(即删除器)
//unique_ptr<objT, declT> p(new objT, fcn);
//p指向一个类型为objT的对象,并使用一个类型为declT的对象释放objT对象,p会调用一个名为fcn的declT类型对象。
//与shared_ptr 传递删除器比较
//shared_ptr<int> p(new int(33), 可调用对象);
//unique_ptr<int, decltype(可调用对象)*> u(new int(22), 可调用对象); //使用decltype来指明函数指针类型。由于decltype(可调用对象)返回一个函数类型,所以我们必须添加一个*来指出我们正在使用该类型的一个指针。
//shared_ptr 无需在尖括号中标明删除器类型,后创建时直接传入可调用对象即可。
getchar();
return 0;
}
c++11新标准:初识智能指针
于 2021-04-10 15:22:54 首次发布