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
,当然这个代码不可能运行成功,只是方便理解。
注意事项:
-
不要混用智能指针和普通指针,你很难注意智能指针什么时候会自动释放,这时再用普通指针访问会发生错误。
-
不要用智能指针的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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
2020-03-13 C++ 传递数组引用