智能指针模板类
什么是智能指针
智能指针是一个类对象,行为类似于指针。
智能是相对于常规指针,常规指针指向的内存,不使用时,需要调用释放函数。但经常会被遗漏或异常时没有处理,造成内存泄漏。智能指针就是为了解决此问题。智能指针对象过期时,可以在智能指针类的析构函数中释放指向的内存,实现自动释放,避免内存泄漏。
三种智能指针
- auto_ptr //C++98 提供的解决方案,C++11已经将其摒弃。
- unique_ptr
- shared_ptr
相对于常规指针,unique_ptr和shared_ptr的行为与auto_ptr的行为相同。
ps:不讨论智能指针weak_ptr
声明指针
#include <memory> //需要包含头文件文件memory, 名称空间为std
auto_ptr<double> pd(new double);
auto_ptr<string> ps(new string);
unique_ptr<double> pdu(new double);
unique_ptr<string> psu(new string);
shared_ptr<double> pds(new double);
shared_ptr<string> pss(new string);
智能指针的构造函数
所有智能指针类都有一个 explicit 构造函数,表明该构造函数是显示的, 而非隐式的, 跟它相对应的另一个关键字是implicit, 意思是隐藏的,类构造函数默认情况下即声明为implicit(隐式).
构造函数将指针作为参数。声明为explicit 是为了避免错误的类型转换。
智能指针实现策略
- 建立所有权(ownership):只有一个智能指针可以拥有对象,释放时由拥有对象的智能指针删除该对象。赋值操作转让所有权,失去所有权的智能指针不再引用该对象。auto_ptr 和 unique_ptr 都是基于该策略, unique_ptr 的策略更加严格。
- 对引用计数:多个智能指针可以指向一个对象,每次引用+1,去引用时-1,计数为0时释放对象。 share_ptr 采用该策略。
unique_ptr 优于 auto_ptr
转让所有权,避免了重复删除对象的问题。转让所有权后的指针为空,试图使用会导致异常。
使用 unique_ptr 可避免这个问题。 如果避免转让所有权后还有使用的可能时,编译器会禁止该赋值行为。
auto_ptr<string> p1(new string("auto"));
auto_ptr<string> p2;
p2 = p1; //OK
unique_ptr<string> p3(new string("unique"));
unique_ptr<string> p4;
p4 = p3; //编译错误 赋值后使用p3会导致异常,编译器禁止这样的赋值
只有赋值为函数返回临时 unique_ptr 或 临时右值 unique_ptr 才允许, 因为转让所有权后的unique_ptr没有机会被使用。
//函数返回临时unique_ptr
unique_ptr<string> demo(const char *s){
unique_ptr<string> temp(new string(s));
return temp;
}
unique_ptr<string> ps;
ps = demo("Uniquely special"); //OK
//临时右值unique_ptr
unique_ptr<string> ps;
ps = unique_ptr<string>(new string "Uniquely special"); //OK
std::move()
unique_ptr<string> p3(new string("unique"));
unique_ptr<string> p4;
p4 = p3; //编译错误
只有赋值后,解引用p3时,才会有问题。 如果是赋予新值是不会有问题的。
编译器禁止是为了避免错误的使用p3, 如果就想执行 p4 = p3,怎么办?
使用std::move(), 可以将一个unique_ptr指针赋值给另一个。
unique_ptr 另一个好处
auto_ptr 使用的是delete, 而不是delete[]. 因此只能和new一起使用。
只有 unique_ptr 有delete[]版本。
- 使用new 分配内存,可以使用智能指针 auto_ptr, unique_ptr, shared_ptr。
- 使用new[]分配内存,只能使用 unique_ptr。
- 其它方式的分配内存,不能使用智能指针。
选择智能指针
- 如果要多个指向同一个对象的指针,使用 shared_ptr.
- 如果不需要多个指向同一个对象的指针,使用 unique_ptr。
- 使用unique_ptr的情况都可以使用auto_ptr, 但 unique_ptr是更好的选择。
- STL容器中,如果有复制或复制操作,使用 shared_ptr, 没有可以使用 unique_ptr。
- STL容器中,unique_ptr 使用push_back() 没有问题,因为 push_back() 返回临时unique_ptr。unique_ptr 使用 for_each()不行,因为右值为非临时unique_ptr。