c++——智能指针学习(shared_ptr和weak_ptr)
先看一个例子:Stark和Targaryen家族你中有我,我中有你。我们设计以下类企图避免内存泄漏,使得析构函数都能调用到:
#include<iostream>
#include<memory>
using namespace std; class Stark;
class Targaryen; class Stark
{
private:
Targaryen *targaryen; public:
void prin(){cout<<"stark love targaryen"<<endl;}
~Stark()
{
delete targaryen;
cout<<"~Stark"<<endl;
}
}; class Targaryen
{
private:
Stark *stark; public:
void prin() { cout << "targaryen love stark" << endl; }
~Targaryen()
{
delete stark;
cout << "~Targaryen" << endl;
}
}; int main()
{
Targaryen *tar = new Targaryen;
Stark *stark = new Stark; delete stark; system("pause");
return 0;
}
打印结果:

正常来说,我们要求的结果是两个对象都要析构掉,但是我们可以debug执行看到,并没有全部析构,显然不是我们的需求!
那么换一种智能指针的写法,看看结果怎么样:
class Stark;
class Targaryen; class Stark
{
private:
//Targaryen *targaryen;
shared_ptr<Targaryen> share_tar;
public:
void prin(){cout<<"stark love targaryen"<<endl;}
void setTargaryen(shared_ptr<Targaryen> tar)
{
this->share_tar = tar;
}
~Stark()
{
//delete targaryen;
cout<<"~Stark"<<endl;
}
}; class Targaryen
{
private:
//Stark *stark;
shared_ptr<Stark> share_stark;
//weak_ptr<Stark> weak_stark; public:
void prin() { cout << "targaryen love stark" << endl; }
void setStark(shared_ptr<Stark> stark)
{
this->share_stark = stark;
}
~Targaryen()
{
//delete stark;
cout << "~Targaryen" << endl;
}
}; int main()
{
weak_ptr<Stark> wpstark;
weak_ptr<Targaryen> wptar; //Targaryen *tar = new Targaryen;
//Stark *stark = new Stark;
{
shared_ptr<Targaryen> tar(new Targaryen);
shared_ptr<Stark> stark(new Stark);
tar->prin();
stark->prin();
tar->setStark(stark);
stark->setTargaryen(tar);
wpstark = stark;
wptar = tar;
cout << tar.use_count() << endl;
cout << stark.use_count() << endl;
} cout << wpstark.use_count() << endl;
cout << wptar.use_count() << endl; //delete stark; system("pause");
return 0;
}
我们希望在main中第一对{}号结束的时候,打印析构函数,但是并没有

那我们再换一种写法:
class Stark;
class Targaryen; class Stark
{
private:
//Targaryen *targaryen;
shared_ptr<Targaryen> share_tar;
public:
void prin(){cout<<"stark love targaryen"<<endl;}
void setTargaryen(shared_ptr<Targaryen> tar)
{
this->share_tar = tar;
}
~Stark()
{
//delete targaryen;
cout<<"~Stark"<<endl;
}
}; class Targaryen
{
private:
//Stark *stark;
//shared_ptr<Stark> share_stark; ////这里变了~~~~~~~~~~~~
weak_ptr<Stark> weak_stark; public:
void prin() { cout << "targaryen love stark" << endl; }
void setStark(shared_ptr<Stark> stark)
{
this->weak_stark = stark;
}
~Targaryen()
{
//delete stark;
cout << "~Targaryen" << endl;
}
};
这次结果还是令人满意的。

那么问题来了,为什么要这么做呢?为什么要用weak_ptr取代shared_ptr呢?
我们看weak_ptr的官方定义:
std::weak_ptr 是一种智能指针,它对被 std::shared_ptr 管理的对象存在非拥有性(“弱”)引用。在访问所引用的对象前必须先转换为 std::shared_ptr。
std::weak_ptr 用来表达临时所有权的概念:当某个对象只有存在时才需要被访问,而且随时可能被他人删除时,可以使用 std::weak_ptr 来跟踪该对象。需要获得临时所有权时,则将其转换为 std::shared_ptr,此时如果原来的 std::shared_ptr 被销毁,则该对象的生命期将被延长至这个临时的 std::shared_ptr 同样被销毁为止。
std::weak_ptr 的另一用法是打断 std::shared_ptr 所管理的对象组成的环状引用。若这种环被孤立(例如无指向环中的外部共享指针),则 shared_ptr 引用计数无法抵达零,而内存被泄露。能令环中的指针之一为弱指针以避免此情况。
这种就是一种环状的情况。
另外,还有一点要注意:
int main()
{
{
int *a = new int;
std::shared_ptr<int> p1(a);
std::shared_ptr<int> p2(a);
}
system("pause");
return ;
}
这样写会报错。因为,析构的时候,指针a会被delete两次。因此,为了避免这种情况的发生,我们尽可能不适用new来初始化shared_ptr。而是用make_shared;
class Mars
{
public:
Mars ()
{
cout << this << ": Mars" << endl;
}
~Mars()
{
cout << this << ": ~Mars" << endl;
}
};
int main()
{
{
Mars pMars;
shared_ptr<Mars> p1 = make_shared<Mars >(pMars);
shared_ptr<Mars> p2 = make_shared<Mars >(pMars);
}
system("pause");
return ;
}
这玩意儿太复杂了~只是清楚大概是干什么的。但是还不会用……以及什么时候用,关键是我们这公司平时也不用,这就尴尬了。
用shared_ptr,不用new
使用weak_ptr来打破循环引用
用make_shared来生成shared_ptr
用enable_shared_from_this来使一个类能获取自身的shared_ptr
结束!以后有时间再慢慢研究。
大部分都是抄的:
https://zh.cppreference.com/w/cpp/memory/shared_ptr
https://www.cnblogs.com/wxquare/p/4759020.html
https://blog.csdn.net/worldwindjp/article/details/18843087
https://heleifz.github.io/14696398760857.html
c++——智能指针学习(shared_ptr和weak_ptr)的更多相关文章
- C++ | 再探智能指针(shared_ptr 与 weak_ptr)
上篇博客我们模拟实现了 auto_ptr 智能指针,可我们说 auto_ptr 是一种有缺陷的智能指针,并且在C++11中就已经被摈弃掉了.那么本章我们就来探索 boost库和C++11中的智能指针以 ...
- C++11 新特性之智能指针(shared_ptr, unique_ptr, weak_ptr)
这是C++11新特性介绍的第五部分,涉及到智能指针的相关内容(shared_ptr, unique_ptr, weak_ptr). shared_ptr shared_ptr 基本用法 shared_ ...
- C++智能指针: auto_ptr, shared_ptr, unique_ptr, weak_ptr
本文参考C++智能指针简单剖析 内存泄露 我们知道一个对象(变量)的生命周期结束的时候, 会自动释放掉其占用的内存(例如局部变量在包含它的第一个括号结束的时候自动释放掉内存) int main () ...
- Qt 智能指针学习(7种指针)
Qt 智能指针学习 转载自:http://blog.csdn.net/dbzhang800/article/details/6403285 从内存泄露开始? 很简单的入门程序,应该比较熟悉吧 ^_^ ...
- C++ 智能指针学习
C++ Code 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849 ...
- 【C++11新特性】 C++11智能指针之shared_ptr
C++中的智能指针首先出现在“准”标准库boost中.随着使用的人越来越多,为了让开发人员更方便.更安全的使用动态内存,C++11也引入了智能指针来管理动态对象.在新标准中,主要提供了shared_p ...
- C++智能指针之shared_ptr与右值引用(详细)
1. 介绍 在 C++ 中没有垃圾回收机制,必须自己释放分配的内存,否则就会造成内存泄露.解决这个问题最有效的方法是使用智能指针(smart pointer).智能指针是存储指向动态分配(堆)对象指针 ...
- 智能指针之shared_ptr基本概述
1.shared_ptr允许有多个指针指向同一个对象,unique_ptr独占所指向的对象. 2.类似于vector,智能指针也是模板.创建智能指针: shared_ptr<string> ...
- 【STL学习】智能指针之shared_ptr
前面已经学习过auto_ptr,这里补充另外一种智能指针,比auto_ptr要更强力更通用的shared_ptr. shared_ptr 简介及使用选择 几乎所有的程序都需要某种形式的引用计数智能指 ...
随机推荐
- 请解释ASP.NET 中的web 页面与其隐藏类之间的关系?
一个ASP.NET 页面一般都对应一个隐藏类,一般都在ASP.NET 页面的声明中指定了隐藏类例如一个页面 Tst1.aspx 的页面声明如下 <%@ Page language="c ...
- 微信小程序swiper 前后边距的使用
小程序中有一个组件swiper 就是滑块视图容器 其中提供了两个属性 previous-margin:前边距,可用于露出前一项的一小部分 next-margin:后边距,可用于露出后一项的 ...
- Shiro的认识
#2019.2.2 Apache Shiro是基于java的一个安全框架.他帮助我们完成:认证.授权.加密.会话管理.web集成.缓存等问题. 在了Shiro之前,先要了解一下什么是权限管理? 权限管 ...
- 二叉树:B+tree等
二叉树:(树是一种可以递归定义数据结构) 度:节点的个数 深度:层数(即从根点到叶子节点的层数) 满二叉树:指底层叶子节点左右均存在的二叉树. 完全二叉树:指底层叶子节点的右侧均存在的二叉树. 一般二 ...
- myls
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <unist ...
- Delphi编程之爬取贴吧帖子图片
大家如果经常在逛贴吧的时候,会看到很多帖子里有很多好看的图片,都想下载下来留存的话,常规的方法只能一张一张点击右键,然后图片另存为,这样的方法对于图片少的来说没什么,要是图片超过100张,200张,那 ...
- Linux批量复制文件到文件夹
echo dirname* | xargs -n 1 cp -v filename 把当前目录下 filename文件拷贝到以dirname开头的不同文件夹里.
- JAVA 集合 按照某个字段(依据一定条件)进行分组
由于数据不能够在本地化实现, 无法通过sql语句得到对应的结果,小编只好在业务层处理.通过调用接口得到集合,拿到集合后,通过年来分组,以此来达到对应的Map集合... 在这里小编给大家提供一个封装了一 ...
- hadoop day 7
1.storm概述 应用于实时的流式计算,结合消息队列和数据库进行使用. Spouts:拓扑的消息源 Bolts:拓扑的处理逻辑单元,每个bolt可以在集群当中多实例的并发执行 tuple:消息元组, ...
- Django 1.9 + celery + django-celry 实现定时任务
celery可以进行任务异步处理,celery还有一种Celery的常用模式便是执行定期任务. 执行定期任务时, Celery会通过celerybeat进程来完成. Celerybeat会保持运行, ...