shared_ptr的使用


前言

shared_ptr又称计数指针或共享指针,与unique_ptr不同的是它是可以共享数据的。shared_ptr原理:shared_ptr创建了一个计数器与类对象所指的内存相关联,copy则计数器加1,销毁则计数器减1,api为use_count()。


一、常用类型的shared_ptr

先来看看代码:

#include<iostream>
#include<memory>
#include"cat.h"
using namespace std;


int main(int argc, char *argv[])
{
    //常量类型
    std::shared_ptr<int> i_p_1=make_shared<int>(10);
    //std::shared_ptr<int> i_p_1=make_shared<int>{new int(10)};
    cout<<"value : "<<*i_p_1<<endl;
    cout<<"use count:"<<i_p_1.use_count()<<endl;
    //copy
    std::shared_ptr<int> i_p_2=i_p_1;
    cout<<"i_p_1 use count:"<<i_p_1.use_count()<<endl;
    cout<<"i_p_2 use count:"<<i_p_2.use_count()<<endl;
    //change
    *i_p_2=30;
    cout<<"i_p_1 value:"<<*i_p_1<<endl;
    cout<<"i_p_2 value:"<<*i_p_2<<endl;
    i_p_2=nullptr;
    cout<<"i_p_1 use count:"<<i_p_1.use_count()<<endl;
    cout<<"i_p_2 use count:"<<i_p_2.use_count()<<endl;
    cout<<"----- yz -----"<<endl;
    return 0;
}

执行结果:
在这里插入图片描述
上述代码中,如果将i_p_1置空会怎么样?

#include<iostream>
#include<memory>
#include"cat.h"
using namespace std;


int main(int argc, char *argv[])
{
    //常量类型
    std::shared_ptr<int> i_p_1=make_shared<int>(10);
    //std::shared_ptr<int> i_p_1=make_shared<int>{new int(10)};
    cout<<"value : "<<*i_p_1<<endl;
    cout<<"use count:"<<i_p_1.use_count()<<endl;
    //copy
    std::shared_ptr<int> i_p_2=i_p_1;
    cout<<"i_p_1 use count:"<<i_p_1.use_count()<<endl;
    cout<<"i_p_2 use count:"<<i_p_2.use_count()<<endl;
    //change
    *i_p_2=30;
    cout<<"i_p_1 value:"<<*i_p_1<<endl;
    cout<<"i_p_2 value:"<<*i_p_2<<endl;
    //i_p_2=nullptr;
    i_p_1=nullptr;
    cout<<"i_p_1 use count:"<<i_p_1.use_count()<<endl;
    cout<<"i_p_2 use count:"<<i_p_2.use_count()<<endl;
     cout<<"----- yz -----"<<endl;
    return 0;
}

执行结果:
在这里插入图片描述
结论:如果将i_p_1置空,i_p_2的引用计数器值由2变为1。

补充实验:再生成一个指向该对象的指针用于验证引用计数器。

#include<iostream>
#include<memory>
#include"cat.h"
using namespace std;


int main(int argc, char *argv[])
{
    //常量类型
    std::shared_ptr<int> i_p_1=make_shared<int>(10);
    //std::shared_ptr<int> i_p_1=make_shared<int>{new int(10)};
    cout<<"value : "<<*i_p_1<<endl;
    cout<<"use count:"<<i_p_1.use_count()<<endl;
    //copy
    std::shared_ptr<int> i_p_2=i_p_1;
    cout<<"i_p_1 use count:"<<i_p_1.use_count()<<endl;
    cout<<"i_p_2 use count:"<<i_p_2.use_count()<<endl;
    //change
    *i_p_2=30;
    cout<<"i_p_1 value:"<<*i_p_1<<endl;
    cout<<"i_p_2 value:"<<*i_p_2<<endl;
    //i_p_2=nullptr;
    i_p_1=nullptr;
    std::shared_ptr<int> i_p_3=i_p_1;
    cout<<"i_p_1 use count:"<<i_p_1.use_count()<<endl;
    cout<<"i_p_2 use count:"<<i_p_2.use_count()<<endl;
    cout<<"i_p_3 use count:"<<i_p_3.use_count()<<endl;
     cout<<"----- yz -----"<<endl;
    return 0;
}

执行结果:
在这里插入图片描述
结论:无论多少个计数指针指向nullptr,nullptr的引用计数值都为0。

实验:让i_p_3指向i_p_1,然后将i_p_1置空

#include<iostream>
#include<memory>
#include"cat.h"
using namespace std;


int main(int argc, char *argv[])
{
    //常量类型
    std::shared_ptr<int> i_p_1=make_shared<int>(10);
    //std::shared_ptr<int> i_p_1=make_shared<int>{new int(10)};
    cout<<"value : "<<*i_p_1<<endl;
    cout<<"use count:"<<i_p_1.use_count()<<endl;
    //copy
    std::shared_ptr<int> i_p_2=i_p_1;
    cout<<"i_p_1 use count:"<<i_p_1.use_count()<<endl;
    cout<<"i_p_2 use count:"<<i_p_2.use_count()<<endl;
    //change
    *i_p_2=30;
    cout<<"i_p_1 value:"<<*i_p_1<<endl;
    cout<<"i_p_2 value:"<<*i_p_2<<endl;
    //i_p_2=nullptr;
    std::shared_ptr<int> i_p_3=i_p_1;
    i_p_1=nullptr;
    cout<<"i_p_1 use count:"<<i_p_1.use_count()<<endl;
    cout<<"i_p_2 use count:"<<i_p_2.use_count()<<endl;
    cout<<"i_p_3 use count:"<<i_p_3.use_count()<<endl;
     cout<<"----- yz -----"<<endl;
    return 0;
}

执行结果:
在这里插入图片描述
结果分析:i_p_2和i_p_3的引用计数值相同。

二、自定义类型的shared_ptr

对自定义的cat类使用shared_ptr:

#include<iostream>
#include<memory>
#include"cat.h"
using namespace std;


int main(int argc, char *argv[])
{
    
     //自定义变量
    std::shared_ptr<Cat> c_p_1=make_shared<Cat>();
    cout<<"c_p_1 use cout : "<<c_p_1.use_count()<<endl;
    std::shared_ptr<Cat> c_p_2=c_p_1;
    std::shared_ptr<Cat> c_p_3=c_p_1;
    cout<<"c_p_1 use cout : "<<c_p_1.use_count()<<endl;
    cout<<"c_p_2 use cout : "<<c_p_2.use_count()<<endl;
    cout<<"c_p_3 use cout : "<<c_p_3.use_count()<<endl;
    cout<<"----- yz -----"<<endl;
    return 0;
}

实验结果:
在这里插入图片描述修改其中一个值会怎样?

std::shared_ptr<Cat> c_p_1=make_shared<Cat>();
    cout<<"c_p_1 use cout : "<<c_p_1.use_count()<<endl;
    std::shared_ptr<Cat> c_p_2=c_p_1;
    std::shared_ptr<Cat> c_p_3=c_p_1;
    cout<<"c_p_1 use cout : "<<c_p_1.use_count()<<endl;
    cout<<"c_p_2 use cout : "<<c_p_2.use_count()<<endl;
    cout<<"c_p_3 use cout : "<<c_p_3.use_count()<<endl;
    c_p_1.reset();//在这个清空c_p_1
    cout<<"c_p_1 use cout : "<<c_p_1.use_count()<<endl;
    cout<<"c_p_2 use cout : "<<c_p_2.use_count()<<endl;
    cout<<"c_p_3 use cout : "<<c_p_3.use_count()<<endl;
    cout<<"----- yz -----"<<endl;

实验结果:
在这里插入图片描述
结论:无论有多少个计数指针指向同一个对象,该对象都只销毁一次。

三、shared_ptr与函数调用

1.pass by value
使用copy语义,智能指针内部计数器加一。

#include<iostream>
#include<memory>
#include"cat.h"
using namespace std;
void cat_by_value(std::shared_ptr<Cat> cat)
{
    cout<<cat->get_name()<<endl;
    cout<<"func use count:"<<cat.use_count()<<endl;
}
int main(int argc, char *argv[])
{
    std:shared_ptr<Cat> c1=make_shared<Cat>("dd");
    cat_by_value(c1);
    c1->cat_info();
    cout<<"c1 use count :"<<c1.use_count()<<endl;
     cout<<"----- yz -----"<<endl;
    return 0;
}

实验结果:
在这里插入图片描述
结论:函数调用完成后销毁的是指针而不是指针指向的内存。

实验:在函数调用内部修改成员变量:

#include<iostream>
#include<memory>
#include"cat.h"
using namespace std;
void cat_by_value(std::shared_ptr<Cat> cat)
{
    cout<<cat->get_name()<<endl;
    cat->set_cat_name("ee");
    cout<<"func use count:"<<cat.use_count()<<endl;
}
int main(int argc, char *argv[])
{
    std:shared_ptr<Cat> c1=make_shared<Cat>("dd");
    cat_by_value(c1);
    c1->cat_info();
    cout<<"c1 use count :"<<c1.use_count()<<endl;
     cout<<"----- yz -----"<<endl;
    return 0;
}

实验结果:
在这里插入图片描述
实验结论:如果在函数调用里边修改了对象里边的成员,那么这个修改是持久的

2 .pass by ref
实验:

#include<iostream>
#include<memory>
#include"cat.h"
using namespace std;
void cat_by_value(std::shared_ptr<Cat> cat)
{
    cout<<cat->get_name()<<endl;
    cat->set_cat_name("ee");
    cout<<"func use count:"<<cat.use_count()<<endl;
}
void cat_by_ref(std::shared_ptr<Cat> &cat)
{
    cout<<cat->get_name()<<endl;
    cat.reset(new Cat());
    cout<<"func use count:"<<cat.use_count()<<endl;
}
int main(int argc, char *argv[])
{
    std:shared_ptr<Cat> c1=make_shared<Cat>("dd");
    cat_by_value(c1);
    c1->cat_info();
    cout<<"c1 use count :"<<c1.use_count()<<endl;
    cat_by_ref(c1);
    c1->cat_info();
     cout<<"----- yz -----"<<endl;
    return 0;
}

实验结果:
在这里插入图片描述
结论:从“ee"的下一行输出我们可以知道,当引用计数器为0时,对象自动销毁。
3.链式调用

#include<iostream>
#include<memory>
#include"cat.h"
using namespace std;


void cat_by_ref(const std::shared_ptr<Cat> &cat)
{
    cout<<cat->get_name()<<endl;
    //cat.reset(new Cat());
    cout<<"func use count:"<<cat.use_count()<<endl;
}
std::shared_ptr<Cat> get_shared_ptr()
{
    std::shared_ptr<Cat> cat_p=std::make_shared<Cat>("local cat");
    return cat_p;
}
int main(int argc, char *argv[])
{
    std:shared_ptr<Cat> c1=make_shared<Cat>("dd");
    c1->cat_info();
    cout<<"c1 use count :"<<c1.use_count()<<endl;
    cat_by_ref(c1);
    c1->cat_info();
    std::shared_ptr<Cat> c_p=get_shared_ptr();
    c_p->cat_info();
    c1=c_p;
    cout<<"c_p use count:"<<c_p.use_count()<<endl;
    cout<<"c1 use count:"<<c1.use_count()<<endl;
     cout<<"----- yz -----"<<endl;
    return 0;
}

实验结果
在这里插入图片描述
实验结论:当c1指向c_p时,c1原来指向的对象引用计数器变为0,原来的对象于是被销毁。

补充实验:

int main(int argc, char *argv[])
{
    std::shared_ptr<Cat> c_p=get_shared_ptr();
    c_p->cat_info();
    get_shared_ptr();
    get_shared_ptr();
    cout<<"c_p use count:"<<c_p.use_count()<<endl;
     cout<<"----- yz -----"<<endl;
    return 0;
}

实验结果:
在这里插入图片描述
实验结论:
每次调用链式函数的时候,都会开辟一块新的内存,如果调用结果后,没有参数接收返回值,那么该内存对应的对象引用计数器减为0,于是对象自动销毁。

四、shared_ptr与unique_ptr

不能将shared_ptr转换为unique_ptr, 但通过std::move,unique_ptr可以转换为shared_ptr。将你的函数返回unique_ptr是一种常见的设计模式,这样可以提高代码的利用度,你可以随时改变为shared_ptr
1.unique_ptr转换为shared_ptr

#include<iostream>
#include<memory>
#include"cat.h"
using namespace std;

std::unique_ptr<Cat> get_unique_ptr()
{
    std::unique_ptr<Cat> cat_p=std::make_unique<Cat>("local cat");
    return cat_p;
}
int main(int argc, char *argv[])
{
    std::unique_ptr<Cat> c_p_1=std::make_unique<Cat>("dd");
    std::shared_ptr<Cat> c_p_2=std::move(c_p_1);
    cout<<"c_p_2 use count:"<<c_p_2.use_count()<<endl;
    cout<<"----- yz -----"<<endl;
    return 0;
}

实验结果:
在这里插入图片描述
实验结论:unique_ptr能通过move语义转变为shared_ptr.
2.用shared_ptr接收unique_ptr

#include<iostream>
#include<memory>
#include"cat.h"
using namespace std;

std::unique_ptr<Cat> get_unique_ptr()
{
    std::unique_ptr<Cat> cat_p=std::make_unique<Cat>("local cat");
    return cat_p;
}
int main(int argc, char *argv[])
{
    std::unique_ptr<Cat> c_p_1=std::make_unique<Cat>("dd");
    std::shared_ptr<Cat> c_p_2=std::move(c_p_1);
    cout<<"c_p_2 use count:"<<c_p_2.use_count()<<endl;
    //func
    std::shared_ptr c_p_3=get_unique_ptr();
    if(c_p_3)
    {
        c_p_3->cat_info();
        cout<<"c_p_3 use count: "<<c_p_3.use_count()<<endl;
    }
    cout<<"----- yz -----"<<endl;
    return 0;
}

实验结果:
在这里插入图片描述
实验结论:unique_ptr能用shared_ptr来接收

3.不能用unique_ptr接收shared_ptr
在这里插入图片描述
4.不允许shared_ptr变量直接对unique_ptr变量进行接收。
在这里插入图片描述
5.shared_ptr变量可以用unique_ptr初始化

int main(int argc, char *argv[])
{
    std::unique_ptr<Cat> c_p_1=std::make_unique<Cat>("dd");
    std::shared_ptr<Cat> c_p_2=move(c_p_1);
    cout<<"c_p_2 use count:"<<c_p_2.use_count()<<endl;

    //func
    std::shared_ptr c_p_3=std::make_unique<Cat>("ab");
    if(c_p_3)
    {
        c_p_3->cat_info();
        cout<<"c_p_3 use count: "<<c_p_3.use_count()<<endl;
    }
     cout<<"----- yz -----"<<endl;
    return 0;
}

实验结果:
在这里插入图片描述
补充实验:

int main(int argc, char *argv[])
{
    std::unique_ptr<Cat> c_p_1=std::make_unique<Cat>("dd");
    std::shared_ptr<Cat> c_p_2=move(c_p_1);
    cout<<"c_p_2 use count:"<<c_p_2.use_count()<<endl;
    //func
    std::shared_ptr c_p_3=std::make_unique<Cat>("ab");
    if(c_p_3)
    {
        c_p_3->cat_info();
        cout<<"c_p_3 use count: "<<c_p_3.use_count()<<endl;
    }
    c_p_2=c_p_3;
    cout<<"c_p_3 use count: "<<c_p_3.use_count()<<endl;
     cout<<"----- yz -----"<<endl;
    return 0;
}

在这里插入图片描述
结论:用shared_ptr定义的变量一定是shared_ptr类型的。


总结

以上为shared_ptr的使用方法,如果有不足的地方,欢迎指出。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇

)">
下一篇>>