实例代码:

// 

#include <iostream>
#include <vector>
#include <memory>


using namespace std;

unique_ptr<string> tuniqp(){
	//unique_ptr<string> pr(new string("I Love China!"));
	//return pr; //从函数返回一个局部的unique_ptr对象。
				//返回这种局部对象,导致系统给我们生成一个临时unique_ptr对象,调用unique_ptr的移动构造函数。
	return unique_ptr<string>(new string("I Love China!"));
}

void mydeleter(string* pdel){
	delete pdel;
	pdel = nullptr;
	// 这里可以打印一下日志。
}

void myfunc(){
	string * ps = new string("I Love China!");
	string * ps2 = new string("I Love China!");
	//...
	//...
	if (true) {
		delete ps; //容易被新手遗忘的语句
		delete ps2;
		return;
	}

	delete ps;
	delete ps2;
	return;
}


int main()
{
	//一、 返回unique_ptr
	//虽然unique_ptr智能指针不能拷贝,但是,当这个unique_ptr将要被销毁,是可以拷贝的。最常见用法就是从函数返回一个unique_ptr

	unique_ptr<string> ps;
	ps = tuniqp(); //可以用ps来接,则临时对象直接构造在ps里,如果不接,则临时对象会被释放,同时会释放掉所指向的对象的内存;


	//二、 指定删除器,delete默认删除器;
	// a). 指定删除器
	//格式: unique_ptr<指向的对象类型, 删除器> 智能指针变量名;
	//删除器,可调用对象,比如函数,类重载了()。
	//我们学习过了shared_ptr 删除器,比较简单 shared_ptr<int> p(new int(), mydelete);
	//unique_ptr删除器相对复杂一点,多了一步,先要在类型模板参数中传递进去类型名,然后在参数中再给具体的删除其函数名
	//a.1)
	typedef void(*fp)(string *); // 定义一个函数指针类型,类型名为fp
	unique_ptr<string, fp> ps1(new string("I Love China!"), mydeleter);
	//a.2)
	using fp2 = void(*)(string *); // 用using定义一个函数指针类型,类型名为fp2
	unique_ptr<string, fp2> ps2(new string("I Love China!"), mydeleter);
	//a.3)
	typedef decltype(mydeleter)* fp3; //这里多了一个*, 因为decltype返回的是函数类型void (string*)
								// 加* 表示函数指针类型,现在fp3 应该void *(string *);
	unique_ptr<string, fp3> ps3(new string("I Love China!"), mydeleter);
	//a.4)
	unique_ptr<string, decltype(mydeleter)*> ps41(new string("I Love China!"), mydeleter);
	//a.5) 用lambda 表达式看看写法,lambda 表达式可以理解成带有operator()类类型对象。
	//所以 decltype(mydella) = class{ ... }
	auto mydella = [](string * pdel) {  // 把lambda表达式理解成一个class;
		delete pdel;
		pdel = nullptr;
		//可以打印日志
	};
	unique_ptr<string, decltype(mydella)> ps5(new string("I Love China!"), mydella);

	//b). 指定删除器额外说明
	//shared_ptr : 就算两个shared_ptr指定的删除器不相同,只要他们所指向的对象相同,那么这两个shared_ptr也属于同一个类型。
	//但是unique_ptr不一样,指定unique_ptr中的删除器会影响unique_ptr的类型,所以从灵活性来讲,shared_ptr设计的更灵活;
	//咱们在讲解shared_ptr的时候,删除器不同,但指向类型一样的shared_ptr,可以放到统一个容器里,vector<shared_ptr ...>
	// unique_ptr如果删除器不同,那么就等于整个unique_ptr类型不同,这种类型不同的unique_ptr智能指针是没有办法放到同一个容器里的;

	//三、 尺寸问题 :通常情况下,unique_ptr 尺寸跟裸指针一样:
	string *p;
	int ilenp = sizeof(p); //4字节
	unique_ptr<string> ps31(new string("I Love China!"));
	int ilen = sizeof(ps31); //4字节
	//如果你增加了自己的删除器,则unique_ptr的尺寸可能增加,也可能不增加
	//a) 如果lambda表达式这种删除器,尺寸就没变化
	ilen = sizeof(ps5); // 4字节 尺寸没变化
	//b) 定义一个函数作为删除器
	typedef void(*fp1) (string*);
	unique_ptr<string, fp1> ps32(new string("I Love China!"), mydeleter);
	ilen = sizeof(ps32); //尺寸发生变化,已经是8字节了

	//增加字节对效率有影响,所以自定义删除器要慎用;
	//shared_ptr, 不管你指定什么删除器, shared_ptr的尺寸(大小)都是裸指针的2倍;

	//四、 智能指针总结
	//(4.1) 智能指针背后的设计思想
	// 智能指针主要目的:帮助我们释放内存,以防止我们忘记释放内存时造成的内存泄漏;
	//C++ 98 auto_ptr   == unique_ptr
	//myfunc();

	//(4.2) auto_ptr为什么被废弃
	//auto_ptr : C++ 98时代的智能指针,具有 unique_ptr一部分特性; unique_ptr, shared_ptr,weak_ptr;
	//不能再容器中保存,也不能从函数中返回auto_ptr;
	auto_ptr<string> ps4(new string("I Love China"));
	//auto_ptr<string> ps5 = ps4;// ps5指向字符串,ps4变成空了,这可以防止ps4和ps5析构一个string两次;
	//用ps4(你没有意识到ps4已经空了),代码就会崩溃;
	//这个也是auto_ptr用法上的一个陷阱。

	shared_ptr<string> ps6(new string("I Love China"));
	shared_ptr<string> ps7 = ps6; //ps7 和ps6都有效,强引用计数为2;
	unique_ptr<string> ps8(new string("I Love China"));
	//unique_ptr<string> ps9 = ps8; //编译出错

	//虽然auto_ptr 和unique_ptr都是独占式的,但unique_ptr 这种情况,编译的时候就会报错;
	//而不会默默的把ps7的所有权转移到ps8上,避免后续如果使用ps7导致程序崩溃的问题;
	//当然如果你用移动语义,也能达到auto_ptr的效果:
	shared_ptr<string> ps10(new string("I Love China"));
	shared_ptr<string> ps11 = std::move(ps10); //运用了移动语义

	//(4.2) auto_ptr为什么被废弃

	//auto_ptr被废弃的主要原因:设计的不太好,容易被误用引起潜在的程序崩溃等问题,所以C++ 11启用了unique_ptr来取代auto_ptr
	//C++ 11表示不建议再使用auto_ptr ,强烈建议大家,用unique_ptr取代;unique_ptr比auto_ptr更安全;

	//(4.3) 智能指针的选择
	//shared_ptr, unique_ptr;
	//a). 如果程序要使用多个指向同一个对象的指针,应该选择shared_ptr;
	//b). 如果程序不需要多个指向同一个对象的指针,应该首选unique_ptr;



	system("pause");
}


09-02 17:39