C++ 11引入了智能指针shared_ptr, unique_ptr 以及weak_ptr,三种智能指针都定义在memory头文件中。
本文将主要介绍shared_ptr的使用。
1.Shared_ptr类:
Shard_ptr:类似于vector,智能指针也是模板,所以在创建智能指针的时候,比如要置顶指向的类型。
shared_ptr<string> p1; //shared_ptr可以指向string
shared_ptr<list<int>> p2; //shared_ptr可以指向int的list
操作 | 含义 |
---|---|
shared_ptr sp | 空智能指针,可以指向类型为T的对象 |
p->mem | 等价于(*p).mem |
p.get() | 返回P中保存的指针,要小心使用,若智能指针释放了其对象,返回的指针所指向的对象也就消失了 |
swap(p, q) p.swap(q) | 交换p 和 q的指针 |
make_shared(args) | 返回一个shared_ptr, 指向动态分配的类型T的对象,使用args初始化对象 |
shared_ptr p(q) | p是shared_ptr q的拷贝,此操作会递增q中的计数器。q中的指针必须转换尾T* |
p=q | p和q都是shared_ptr,所保存的指针必须能相互转换,此操作会递减p的引用计数,递增q的引用计数,若p的引用计数变为0,则将其管理的内存释放 |
p.unique() | 若p.use_count() 为1,返回true,否则换回false |
p.use_count() | 返回与p共享对象的智能指针的数量;可能很慢,主要用于调试。 |
2.使用方法
最安全的分配使用动态内存的方法就是调用make_shared函数。
示例:
sharedptr<int> p3 = make_shared<int> (40); //指向一个值为40的int的shared_ptr
shared_ptr<string> p4 = make_shared<string>(10, '9') //指向一个职位"999999999"的string
shared_ptr<int> p5 = make_shared<int>(); //指向一个int(int已经初始化为0)
auto p = make_shared<int> (40); //指向一个值为40的对象,并且只有p一个引用者
auto q(p); //p与q指向相同的对象,此对象有两个引用者
3.shared_ptr优势及原因:
3.1优势:
我们使用sharedptr的主要原因就是shared_ptr可以自动销毁所管理的对象或者释放相关联的内存。
3.2原因:
- 程序不知道自己需要使用多少对象:
- 程序不知道所需对象的准确类型
- 程序需要在多个对象之间共享数据
4.shared_ ptr 和 new 结合使用
如果我们不初始化一个智能指针,它就会被初始化为一个空指针。如下,我们还可以用new返回的指针来初始化智能指针:
shared_ptr<double> pl; // shared_ptr 指向一个double的空指针
shared_ptr<int> p2 (new int(42)); // p2指向一个值为42的int
接受指针参数的智能指针构造函数是explicit的。因此,我们不能将一个内置指针隐式转换为一个智能指针,必须使用直接初始化形式来初始化一个智能指针。同时由于我们不能使用内置指针到智能指针的隐式转换,一个返回shared_ptr 的函数不能在其返回语句中隐式转换一个普通指针:
shared_ptr<int> p1 = new int(1024); // 错误:必须使用直接初始化形式
shared_ptr<int> p2 (new int (1024)); //正确:使用了直接初始化形式
shared_ ptr<int> clone (int p) {
//正确:显式地用int*创建shared_ ptr<int>
return shared_ptr<int> (new int(p) ) ; //错误
}
操作 | 含义 |
---|---|
shared_ptr p(q) | p管理内置指针指向的对象;q必须指向new 分配的内存,且能够转化成为T*类型 |
shared_ptr p(u) | p从unique_ptr u那里接管对象的所有权;将u置为空 |
shared_ptr p(q, d) | p接管了内置指针q所指向的对象所有权。q必须能转换为T*类型。p将使用可调用的对象d来代替delete |
shared_ptr p(p2, d) | p是shared_ptr p2的拷贝,唯一的区别是p将用可调用对象d来代替delete |
p.reset() p.reset(q)p.reset(q.d) | 若p是唯一指向其对象的shared_ptr,reset会释放次对象。若传递了可选参数内置指针q,会令p指向q,否则会将p置为空。若还传递了参数d, 将会调用d而不是delete来释放q |
reset 使用示例:
#include <memory>
#include <iostream>
#include <vector>
#include <string>
class obj
{
private:
int _num;
public:
obj(int num):_num(num) {
std::cout << "obj is constructed and num : " << num << std::endl;
}
~obj() {
std::cout << "obj is deleted and num " << _num << std::endl;
}
};
int main()
{
std::shared_ptr<obj> shared_ptr1(new obj(99));
shared_ptr1.reset(); //会使用~obj()函数进行删除
std::shared_ptr<obj> shared_ptr2(new obj(88));
shared_ptr2.reset(new obj(33), [](obj* p1){ std::cout<<"in reset" << " addr " << (long)p1 <<std::endl; delete p1; });
return 0;
}
输出结果:
obj is constructed and num : 99
obj is deleted and num 99
obj is constructed and num : 88
obj is constructed and num : 33
obj is deleted and num 88
in reset addr 140550200121472
obj is deleted and num 33
5.总结
智能指针确实在动态内存管理上给了程序源一定的方便,但是并不是有了shared_ptr就没有内存泄露的问题,内存泄露依然可能存在。另外并不是越多使用shared_ptr越好,任何可见的方便都是以内在的效率为代价。