1、智能指针
1.1 两种智能指针shared_ptr 和 unique_ptr
 
共有操作:

- 注意:get函数返回的是内置类型的指针,不是智能指针
这样理解shared_ptr:shared_ptr类型的对象可以【共享所有权】,并且可以【分享该所有权】,一旦他们取得了一个指针的所有权,那么当该指针的这一组所有者中【最后一个释放所有权】的需要负责【释放该指针所指向的内存空间】。
 
shared_ptr对象只能通过复制其值来共享所有权。
 
shared_ptr独有的操作:
 

- 使用make_shared构造对象时,如果不传递任何参数,对象就会进行值初始化。
- 在刚刚初始化一个shared_ptr后,他的计数器是否为1或0,在于初始化的时候到底有没有给他一个实际分配了的堆内存空间。
2、直接管理内存(不用智能指针,而是用new 和 delete)
 
2.1 使用new动态分配和初始化对象
 
默认情况下(就是只写一个类型在那里),用new动态分配的对象时默认初始化的。(注意不是值初始化)
 但我们可以在初始化的时候使用 直接初始化(()里面直接写上初值) 、构造函数初始化 、 列表初始化 、以及值初始化(只写一个())。
 
动态分配const对象:
 
const int *pci = new const int(1024);
const string pcs = new const string;
内存耗尽:
int *p1 = new int;					如分配失败,new抛出异常std::bad_alloc
int *p2 = new (nothrow) int;		若分配失败,返回空指针,不抛出异常
2.2 delete
 
delete用于释放内置指针指向的动态分配的对象所占用的动态内存空间。
- delete可以释放【任何】空指针,即使他不是指向动态内存
- delete不能释放非- new定义的指针,准确来说是不能释放指向局部变量(栈空间)的指针
- delete不能两次释放同一个指针
- 不能释放非指针变量
- const对象也是可以被销毁的
- delete一个指针后,指针值就无效了,虽说他还保存着(已经释放了的)动态内存的地址,但里面已经没有数据对象了。最好把它置为- nullptr
2.3 练习题

 答案和分析:
 有错误。
 上面的函数意图通过new返回的指针来判断内存分配成功或失败,若成功,返回合法指针,指针转换成bool类型的true,若p得到nullptr则转换为false。
 但普通new调用在【分配失败】时抛出一个【异常bad_alloc】,而不是返回nullptr,因此程序不能达到预期的目的。
 进行如下修改阻止抛出异常:
int* p = new (nothrow) int;
不过最佳的方法是捕获异常,或判断返回的指针来返回true 或 false,而不是依赖类型转换。
3、shared_ptr 和 new 的混合使用
 
可以用new返回的指针初始化智能指针,如下所示:
shared_ptr<int> p(new int(42));		p2指向值为42的int
但需要注意:只能使用直接初始化方式。
因为接收参数的智能指针构造函数是explicit的,所以不能将一个内置指针隐式转换为一个智能指针,必须直接初始化:
shared_ptr<int> p1 = new int(42);		错误,隐式地要求用int*来转换成shared_ptr
shared_ptr<int> p2(new int(42));		正确
shared_ptr<int> clone(int p)			尤其在函数里要小心这种隐式转换
{
	return new int(p);					隐式转换为shared_ptr
}
同理,一个shared_ptr的指针,也不能隐式的转换为一个普通(内置)指针。
4、shared_ptr的其他构造方法 以及 成员
 


 最好不用内置指针访问之智能指针所指的对象,因为不知道对象和时会被销毁。内置指针很可能会变成悬空的。
5、使用智能指针的注意事项

6、unique_ptr特有的操作
 
6.1 初始化方法
不可赋值初始化,或拷贝初始化。
unique_ptr<int> u1(new int(42));		通过构造函数,直接初始化
unique_ptr<int> u2 = move(u1);			通过移动函数初始化,当然了,u1已经无了
6.2 unique_ptr的操作
 

- unique_ptr和对象绑定在一起,所以没有拷贝 和 赋值操作
- 但是,成员release和reset共同使用可移交指针的所有权
- release返回的是【内置】指针类型。
- 像release这种【不会释放对象】的操作,我们应该用一个指针或智能指针保存release返回的指针,防止其丢失,并且要记得delete掉这个指针。
- unique_ptr也有- get方法,但通常仅用于拿到指针,然后访问内存里的数据,一旦- unique_ptr被释放了,这个指针就不要用了。
6.3 unique_ptr不能拷贝的例外
 
 
例1:
unique_ptr<int> aaa()
{
	unique_ptr<int> u1(new int());
	// 函数的代码
	return u1;								返回值时发生了拷贝				
}
例2:
unique_ptr<int> bbb()
{
	// 函数的代码
	return unique_ptr<int>(new int(42));	返回值时发生了拷贝
}
6.4 指向数组的unique_ptr(动态数组)(不做重点)
 

- 若u指向动态分配的数组,调用u.release(),会自动用delete[]销毁其内存空间和指针。
- shared_ptr不支持管理动态数组,如果希望使用- shared_ptr管理,需要提供自定义的删除器。而且,- shared_ptr也不支持下标访问元素。必须通过- get获取内置指针来访问。
7.1 weak_ptr
 
weak_ptr不共享内存对象的所有权,也就是,他不会控制所指对象的生存期,即使它指向了shared_ptr所管理的对象,也不会另相应shared_ptr计数器增加。这就叫weak
 
- 注意lock成员返回的是一个shared_ptr,所以会递增相应的计数器
8、allocator分配器
 
8.1 标准库分配器及其成员

- 不要用allocate返回的指针去构造,而是应该用另一个指针接收它的值,用另一个指针构造,开始的指针最后用来释放内存。
- construct没有返回值,所以每构造完一个对象,你都得手动- ++指针,只想下一片内存,才能继续构造。
allocator<int> alloc;
auto const p = alloc.allocate(10);	
auto m = p;
alloc.construct(m++);				构造空 string
alloc.construct(m++, 10, 'c');		10个'c'的string		  'construct'的'args'参数可以是这些
alloc.construct(m++, "hi");			"hi"
while (m != p)
	alloc.destroy(--q);				释放的时候,先  'destroy'
	
alloc.deallocate(p, 10);			最后一步
8.2 allocator算法
 

- 经检验,虽说上述4个函数的参数 b和e是说传迭代器,但是传递一个指针也是没有问题的,指针的类型就是allocate返回的指针类型。就是下面的这一长串:
class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > *










