【C++动态指针之shared_ptr】

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原因:

  1. 程序不知道自己需要使用多少对象:
  2. 程序不知道所需对象的准确类型
  3. 程序需要在多个对象之间共享数据

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 
    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 
#include 
#include 
#include 

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越好,任何可见的方便都是以内在的效率为代价。

你可能感兴趣的:(C/C++,c++,开发语言)