C++ 智能指针

智能指针:shared_ptr类

shared_ptr是一个模板类,智能指针本质是个对象,有一些方法可以调用。

shared_ptr<int> p;
p.get();//获得指针的值(内存地址)
p.use_count();//有几个智能指针指向这个内存地址
p.unique();//如果p.use_count()==1,他返回true

这个类也定义了解引用运算符(*)和箭头运算符(->),目的是像使用指针一样使用智能指针。

*p;
p->func();//等价(*p).func();

make_shared() 函数

智能指针有三种初始化方式

shared_ptr<int> p(new int);//用new返回的指针来初始化,但这个构造函数是explicit的,因此,普通指针无法隐式转换成智能指针。
shared_ptr<int> q(p);//用另一个智能指针初始化
shared_ptr<int> p(make_shared<int>(10)); //使用make_shared();他也是一个模板,需要指定类型,后边的括号相当于调用构造函数
//也可以用auto
auto p = make_shared<int>(10);

动态内存会随着智能指针的生命周期而自动释放,当没有一个智能指针指向某块内存,他就会自动释放。也就是p.use_count() == 0,当然这个代码不可能运行成功,只是方便理解。

注意事项:

  1. 不要混用智能指针和普通指针,你很难注意智能指针什么时候会自动释放,这时再用普通指针访问会发生错误。

  2. 不要用智能指针的get()函数来初始化另一个智能指针,这种方法不会增加use_count,因此会double free。

    int main()
    {
    	shared_ptr<C> p(make_shared<C>());
    	shared_ptr<C> q(p.get());
    	cout << p.use_count();//输出1
    	getchar();
    	return 0;
    	//程序结束p和q都会释放内存,double free
    }
    

使用自己的释放操作

引用C++ primer里的例子,假如shared_ptr指向的是一个网络连接,那么我们希望当这个连接不再使用的时候能够自动释放,这就需要自己定义释放函数。

void end_connection(connection *p)
{
    //释放连接
}
void f(destination &d)
{
    connection c = connect(d);
    shared_ptr<connection> p(&c, end_connection);
    //使用连接
    //从f退出时,connection会自动调用end_connection关闭
}

unique_ptr

shared_ptr智能指针可以不同的几个智能指针指向同一块内存,而unique_ptr只允许一个智能指针(不管是shared_ptr还是unique_ptr)指向这块内存。要想将这块内存变成普通的智能指针,使用p.release()

unique_ptr<T> up(new T);
shared_ptr<T> sp(up.release());
up.reset(new int);//重新绑定一个内存地址

unique_ptr使用自己的释放操作

unique_ptr<T, D> p(new T, d);
//D是可调用对象的类型,d是D类型的一个对象
//下边是个例子
void end_connection(connection *p)
{
    //释放连接
}
void f(destination &d)
{
    connection c = connect(d);
    unique_ptr<connection, decltype(end_connection)*> p(&c, end_connection);
    //使用连接
    //从f退出时,connection会自动调用end_connection关闭
}

智能指针循环引用

若干对象中的shared_ptr成环时,环中的智能指针的引用永远不会为0。解决办法是用weak_ptr作为对象中的智能指针,weak_ptr不会增加或减少引用计数。

class A
{
public:
    std::weak_ptr<B> _a;
    ~A()
    {
        std::cout << "class A disconstruct " << std::endl;
    }
};

class B
{
public:
    std::weak_ptr<A> _b;
    ~B()
    {
        std::cout << "class B disconstruct " << std::endl;
    }
};

int main()
{
    std::shared_ptr<A> a_ptr = std::make_shared<A>();
    std::shared_ptr<B> b_ptr = std::make_shared<B>();
    std::cout << "a_ptr use count:" << a_ptr.use_count() << std::endl;
    std::cout << "b_ptr use count:" << b_ptr.use_count() << std::endl;

    a_ptr->_a = b_ptr;
    b_ptr->_b = a_ptr;
    std::cout << "a_ptr use count:" << a_ptr.use_count() << std::endl;
    std::cout << "b_ptr use count:" << b_ptr.use_count() << std::endl;

    return 0;
}
posted @   hellozhangjz  阅读(97)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
历史上的今天:
2020-03-13 C++ 传递数组引用
点击右上角即可分享
微信分享提示