先看一个例子: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)的更多相关文章

  1. C++ | 再探智能指针(shared_ptr 与 weak_ptr)

    上篇博客我们模拟实现了 auto_ptr 智能指针,可我们说 auto_ptr 是一种有缺陷的智能指针,并且在C++11中就已经被摈弃掉了.那么本章我们就来探索 boost库和C++11中的智能指针以 ...

  2. C++11 新特性之智能指针(shared_ptr, unique_ptr, weak_ptr)

    这是C++11新特性介绍的第五部分,涉及到智能指针的相关内容(shared_ptr, unique_ptr, weak_ptr). shared_ptr shared_ptr 基本用法 shared_ ...

  3. C++智能指针: auto_ptr, shared_ptr, unique_ptr, weak_ptr

    本文参考C++智能指针简单剖析 内存泄露 我们知道一个对象(变量)的生命周期结束的时候, 会自动释放掉其占用的内存(例如局部变量在包含它的第一个括号结束的时候自动释放掉内存) int main () ...

  4. Qt 智能指针学习(7种指针)

    Qt 智能指针学习 转载自:http://blog.csdn.net/dbzhang800/article/details/6403285 从内存泄露开始? 很简单的入门程序,应该比较熟悉吧 ^_^ ...

  5. C++ 智能指针学习

     C++ Code  12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849 ...

  6. 【C++11新特性】 C++11智能指针之shared_ptr

    C++中的智能指针首先出现在“准”标准库boost中.随着使用的人越来越多,为了让开发人员更方便.更安全的使用动态内存,C++11也引入了智能指针来管理动态对象.在新标准中,主要提供了shared_p ...

  7. C++智能指针之shared_ptr与右值引用(详细)

    1. 介绍 在 C++ 中没有垃圾回收机制,必须自己释放分配的内存,否则就会造成内存泄露.解决这个问题最有效的方法是使用智能指针(smart pointer).智能指针是存储指向动态分配(堆)对象指针 ...

  8. 智能指针之shared_ptr基本概述

    1.shared_ptr允许有多个指针指向同一个对象,unique_ptr独占所指向的对象. 2.类似于vector,智能指针也是模板.创建智能指针: shared_ptr<string> ...

  9. 【STL学习】智能指针之shared_ptr

    前面已经学习过auto_ptr,这里补充另外一种智能指针,比auto_ptr要更强力更通用的shared_ptr. shared_ptr 简介及使用选择  几乎所有的程序都需要某种形式的引用计数智能指 ...

随机推荐

  1. Java虚拟机学习-对象的创建

    虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载.解析和初始化过.如果没有,必须先执行相应类的加载过程. 类加载 ...

  2. Python PIL

    Python PIL PIL (Python Image Library) 库是Python 语言的一个第三方库,PIL库支持图像存储.显示和处理,能够处理几乎所有格式的图片. 一.PIL库简介 1. ...

  3. Oracle常用sql命令

    1.查看数据库归档是开启还是关闭SQL> archive log list 更改数据库归档模式: SQL> shutdown immediateSQL> startup mountS ...

  4. L358 World Book Day

    World Book Day is celebrated by UNESCO and other related organisations every year on the 23rd of Apr ...

  5. 关于下拉列表HtmlDownlistFor的使用

    1.定义下拉列表需要的数据 public static List<SelectListItem> GetProList() {   List<SelectListItem> i ...

  6. 关于freemarker 空变量的接收以及类型转换 笔记

    通常接收一个变量是${siOrganid},如果并没有这个变量,是这么处理${siOrganid!},如果这个变量是某个类属性,是这么处理${interfsrv.siOrganid!},如果这个类也是 ...

  7. 用http请求一直失败,用https开头就ok了

    今天晚上在调试新浪的程序,发现之前一直可以用的接口,有时候就会失败, 各项参数全部仔细核对,都没有发现任何不同之处,真是奇了怪了. 后来一看,post 的部分,之前是用 http:// 开头的,但是此 ...

  8. EtherCAT主站对PHY有要求?

    /********************************************************************** * EtherCAT主站对PHY有要求? * 说明: * ...

  9. CSS学习笔记_day1

    目录 一. 什么是HTML 二.编辑器 三.Html的基本骨架 四.html基本标签 h.p.img.a.audio.video.ul>li.ol>li.dl dd dt.span.div ...

  10. Api文件

    对于我们不认识的类(只限于java自带的类),我们可以百度去查一下,但是这样是嚼别人吃剩下的骨头,我们可以去查java的api文件,虽然都是英语,但是还是硬着头皮看吧,加油! 链接:https://p ...