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 简介及使用选择 几乎所有的程序都需要某种形式的引用计数智能指 ...
随机推荐
- linux创建新用户,可以使用sudo无密码操作
useradd -d /home/aiuap -m aiuappasswd aiuapXXXXXXXgroupadd aiuapchown -R aiuap:aiuap /home/aiuap chm ...
- 练习 HashSet 去重复
package com.rf.xs.list; import java.util.HashSet; public class Person { private String name; private ...
- node.js学习三--------------------- http服务器模块的搭建
/** * http服务器的搭建,相当于php中的Apache或者java中的tomcat服务器 */ // 导包 const http=require("http"); //创建 ...
- Java程序心得体会
学习Java是一件快乐的事情,刚开始学习的时候还有点难,后来慢慢熟悉了Java的程序操作,在错误中获得技巧,一次又一次的失败,让我对Java产生了兴趣,现在对Java既陌生又熟悉,我相信我会喜欢上Ja ...
- Windows MySQL测试数据库employees的导入
一: 首先下载employees测试数据库 https://launchpad.net/test-db/ 二:用文本编辑器打开其中的employees.sql文件,将第38行的set storage_ ...
- 神州数码DHCP及DHCP中继配置
实验要求:掌握DHCP及DHCP中继配置方法 拓扑如下 R1 enable 进入特权模式 config 进入全局模式 hostname R1 修改名称 interface g0/5 进入端口 ip a ...
- Could not find method google() for arguments [] on repository container,rn 集成react-native-camera 出现此错误的解决方法
(1) app/build.gradle android { compileSdkVersion buildToolsVersion "25.0.2" } compile (pro ...
- 如何在运行时(Runtime)获得泛型的真正类型
前言 由于Java 的类型擦除机制,在编译时泛型都被转为了Object,例如List<String>经过编译之后将变为类型 List.可以通过以下的方式再运行时获得泛型的真正类型 泛型如何 ...
- seg代码配置的踩坑记录
01. SEGMENTATION FAULT 正在配置OCNET的代码,在自己的本地运行没有任何问题,但是在服务器上一直报错:SEGMENTATION FAULT 这属于很概括的报错,无法直接看明白到 ...
- Ubuntu系统下Anaconda使用方法总结
前言:个人认为Anaconda比pip使用起来要方便很多,因为它创建虚拟环境和下载各种库都很方便.但是有时候conda的安装方法中没有某些库,必须使用pip来进行安装.所以,主要用Anaconda,偶 ...