代码1

int main(){
//裸指针,手动开辟,需要自己释放,如果忘记了或者因为
//程序逻辑导致p没有释放,那么就会导致内存泄漏
int *p=new int(10); if(***){
retur -1;
}
delete p;
return 0;
}

有没有什么办法帮我们管理指针,确保资源释放?

智能指针

利用栈上的对象出作用域时自动析构的特征,来做到资源的自动释放

问题:是否可以在堆上创建裸指针?语法上没有问题,但是我们正式希望

栈上对象出作用域能自动析构的特征来达到自动管理指针的目的,如果

将智能指针创建在堆上,那又和原来的裸指针使用遇到的问题是一样的了

需要手动delete

代码2

#include <iostream>
using namespace std; template<typename T>
class MySmartPtr1 { public:
MySmartPtr1(T * ptr=nullptr) : _mptr(ptr) { }
~MySmartPtr1() {
delete _mptr;
_mptr = nullptr;
} T & operator*() { return *_mptr; }//返回的 是 & , 需要修改值
T * operator->() { return _mptr; } private:
T * _mptr; }; int main() {
MySmartPtr1<int> ptr(new int(10));
*ptr= 200;
return 0;
}

代码2的问题

int main() {
MySmartPtr1<int> ptr(new int(10)); //使用ptr 拷贝构造ptr2,默认的拷贝构造方式是值拷贝,所以底层
//_mptr指针 指向的是同一块内存,那么ptr2 和ptr析构的时候就会有问题了,两次析构同一片内存
MySmartPtr1<int> ptr2(ptr);
*mptr = 200;
return 0;
}

如何解决呢?

1:不带引用计数的智能指针

auto_ptr C++库提供

C++11 新标准

scoped_ptr

unique_ptr

代码 关于 auto_ptr

int main() {
auto_ptr<int> ptr1(new int(100));
auto_ptr<int> ptr2(ptr1);
*ptr2 = 200;
cout<<*ptr1<<endl;//执行报错,原因见下图
return 0;
}

现在不推荐使用auto_ptr

容器中推荐用auto_ptr吗? vector<auto_ptr> v1; v2(v1); 容器的拷贝构造和容器的赋值容易引起容器元素的拷贝构造和赋值,而auto_ptr的拷贝构造会将原来管理的底层资源(指针)置空

代码关于 scoped_ptr

int main() {
scope_ptr的处理方式 scope_ptr<int>(const scope_ptr<int> & src)=delete;//通过直接和谐掉这两个方法
scope_ptr<int> & operator=(const scope_ptr<int> & src))=delete;//通过直接和谐掉这两个方法 return 0;
} 所以scoped_ptr使用的也很少

代码关于 unique_ptr

int main() {
unique_ptr的处理方式 unique_ptr<int>(const unique_ptr<int> & src)=delete;//通过直接和谐掉这两个方法
unique_ptr<int> & operator=(const unique_ptr<int> & src))=delete;//通过直接和谐掉这两个方法 unique_ptr<int> ptr1(new int(100));
unique_ptr<int> ptr2(ptr1);//编译报错,尝试使用已经删除的函数, 要改成如下!!! unique_ptr<int> ptr1(new int(100));
unique_ptr<int> ptr2(std::move(ptr1));//编译OK,为什么可以呢?因为unique_ptr提供了右值引用的拷贝构造和右值引用的赋值函数,如下 unique_ptr<int>(const unique_ptr<int> && src){};
unique_ptr<int> & operator=(const unique_ptr<int> && src)){}; return 0;
} //推荐使用

2:带引用计数的智能指针(share_ptr,weak_ptr)

带引用计数的好处:多个智能指针可以管理同一个资源

带引用计数:给每一个对象资源,匹配一个引用计数,

智能指针引用一个资源的时候,给这个资源引用计数加1

当这个智能指针出作用域不再使用资源的时候,给这个资源引用计数-1,当引用计数不为0的时候,还不能析构这个资源,

当引用计数为0的时候,说明已经没有外部资源使用这个资源了,那么就可以析构这个资源了

代码3 简单实现share_ptr

#include <iostream>
using namespace std; template<typename T>
class RefCount { public:
RefCount(T * pSrc = nullptr, int refCount = 0):_pSrc(pSrc),_refCount(refCount) { }
void addCount() { this->_refCount++; }
void deleltCount() { --this->_refCount; }
int refCount() { return this->_refCount; } private:
T * _pSrc;
int _refCount = 0;
}; template<typename T>
class MySmartPtr2 { public: //新创建的智能指针,默认计数器为1
MySmartPtr2<T> (T * mptr=nullptr): _mptr(mptr){
_pRef = new RefCount<T>(_mptr,1);
} //拷贝构造
MySmartPtr2<T>(const MySmartPtr2<T> & _rval) {
//两个智能指针指向相同的资源 this->_mptr = _rval._mptr;
this->_pRef = _rval._pRef;
this->_pRef->addCount();
}
//赋值重载
MySmartPtr2<T> & operator=(const MySmartPtr2<T> & _rval) {
if (this == &_rval) { retur *this; }
else {
this->_pRef->deleltCount();
int currentCount = this->_pRef->refCount();
if (currentCount == 0) {
delete this->_mptr;//销毁指向的资源
this->_mptr = nullptr;
delete _pRef;
_rPef = nullptr;
}
this->_pRef = _rval._pRef;
this->_mptr = _rval._mptr;
this->_pRef->addCount();
return *this;
}
}
~MySmartPtr2<T>() { this->_pRef->deleltCount();
int currentCount = this->_pRef->refCount();
if (currentCount == 0) {
delete this->_mptr;//销毁指向的资源
this->_mptr = nullptr;
delete _pRef;
_pRef = nullptr;
}
} int getRefCount() { return this->_pRef->refCount(); } private:
T * _mptr;
RefCount<T> * _pRef;
}; int main() {
MySmartPtr2<int> ms1(new int(100)) ; {
MySmartPtr2<int> ms2(ms1);
cout << "RefCount=" << ms1.getRefCount() << endl; MySmartPtr2<int> ms3(ms1);
cout << "RefCount=" << ms1.getRefCount() << endl; }
cout << "RefCount=" << ms1.getRefCount() << endl; system("pause"); return 0;
}

share_ptr: 强智能指针,可以改变资源的引用计数

weak_ptr: 弱智能指针,不会改变资源的引用计数

强智能指针:循环引用(交叉引用)是什么问题?什么结果?怎么解决?

交叉引用代码

class A{
pubic:
A(){cout<<"A()"<<endl;}
~A(){cou<<"~A()"<<endl;}
share_ptr<B> _ptrb;
} class B{
pubic:
B(){cout<<"B()"<<endl;}
~B(){cou<<"~B()"<<endl;}
share_ptr<A> _ptrb;
} int main(){ share_ptr<A> pa(new A());
share_ptr<B> pb(new B()); pa->_ptrb=pb;
pb->_ptra=pa; cout<<pa.use_count()<<endl;// 2
cout<<pb.use_count()<<endl;// 2 }

上面代码造成new出来的资源无法释放!!资源泄漏问题

解决:

定义对象的时候,用强智能指针,引用对象的地方用弱智能指针

class A{
pubic:
A(){cout<<"A()"<<endl;}
~A(){cou<<"~A()"<<endl;}
void testA(){
cout<<"A testA() Function"<<endl;
}
weak_ptr<B> _ptrb;
} class B{
pubic:
B(){cout<<"B()"<<endl;}
~B(){cou<<"~B()"<<endl;} void function(){
share_ptr<A> _tp=_ptrb.lock();//提升方法
if(_tp!=nullptr){
_tp->testA();
}
}
weak_ptr<A> _ptrb; //weak_ptr 弱智能指针,不会改变引用计数
} int main(){ share_ptr<A> pa(new A());
share_ptr<B> pb(new B()); pa->_ptrb=pb;
pb->_ptra=pa; pb.function();
cout<<pa.use_count()<<endl;// 2
cout<<pb.use_count()<<endl;// 2 }

share_ptr 和 weak_ptr 是线程安全的.

<一>智能指针基础的更多相关文章

  1. Boost智能指针-基础知识

    简单介绍 内存管理一直是 C++ 一个比較繁琐的问题,而智能指针却能够非常好的解决问题,在初始化时就已经预定了删除.排解了后顾之忧.1998年修订的第一版C++标准仅仅提供了一种智能指针:std::a ...

  2. C++ 中的智能指针-基础

    简介 在现代 C++ 编程中,标准库包含了智能指针(Smart pointers). 智能指针用来确保程序不会出现内存和资源的泄漏,并且是"异常安全"(exception-safe ...

  3. C++ 基础知识回顾(string基础、智能指针、迭代器、容器类)

    [1] string基础 [1.1] string 的构造 #include <iostream> #include <string> int main() { using n ...

  4. [易学易懂系列|rustlang语言|零基础|快速入门|(21)|智能指针]

    [易学易懂系列|rustlang语言|零基础|快速入门|(21)|智能指针] 实用知识 智能指针 我们今天来讲讲Rust中的智能指针. 什么是指针? 在Rust,指针(普通指针),就是保存内存地址的值 ...

  5. c++基础 使用智能指针

    三个智能指针模板(auto_ptr.unique_ptr和shard_ptr)都定义了类似指针的对象(c++11已将auto_ptr摒弃),可以将new获得(直接或间接) 的地址赋给这种对象.当智能指 ...

  6. ndk学习之c++语言基础复习----C++线程与智能指针

    线程 线程,有时被称为轻量进程,是程序执行的最小单元. C++11线程: 我们知道平常谈C++线程相关的东东基本都是基于之后要学习的posix相关的,其实在C++11有自己新式创建线程的方法,所以先来 ...

  7. C++基础--智能指针

    智能指针其实也不是完全的指针,应该说是像指针一样的类对象,智能指针通常有指针的功能,当然同时也包含了一些额外的功能.目前比较常见的智能指针有auto_ptr.unique_ptr和shared_ptr ...

  8. 【UE4 C++ 基础知识】<15> 智能指针 TSharedPtr、UniquePtr、TWeakPtr、TSharedRef

    基本概念 UE4 对 UObject 对象提供垃圾回收 UE4 对原生对象不提供垃圾回收,需要手动进行清理 方式 malloc / free new / delete new与malloc的区别在于, ...

  9. C++智能指针

    引用计数技术及智能指针的简单实现 基础对象类 class Point { public: Point(int xVal = 0, int yVal = 0) : x(xVal), y(yVal) { ...

  10. C++ 引用计数技术及智能指针的简单实现

    一直以来都对智能指针一知半解,看C++Primer中也讲的不够清晰明白(大概是我功力不够吧).最近花了点时间认真看了智能指针,特地来写这篇文章. 1.智能指针是什么 简单来说,智能指针是一个类,它对普 ...

随机推荐

  1. 第五章:Admin管理后台 - 3:Admin文档生成器

    Django的admindocs应用可以从模型.视图.模板标签等地方获得文档内容. 一.概览 要激活admindocs,请按下面的步骤操作: 在INSTALLED_APPS内添加django.cont ...

  2. windows系统下使用bat脚本文件设置 JDK 系统环境变量

    号开头的行不要写在bat文件中 # java_init.bat # 注意文件换行符是windows系统下的(CR LF),文件编码是ANSI # path变量追加这个可以拓展到tomcat,mysql ...

  3. Grafana配置Alert监控告警

    1.添加告警途径 这里以slack为例 测试是否可用 在slack上收到告警通知了 安装插件 # grafana-cli plugins install grafana-image-renderer ...

  4. Python离线安装Flask

    受限于内网,无法使用pip install Flask直接安装. 以Flask-0.12.2为例 安装Flask需要以下的依赖性,在安装Flask离线版时可以看到依赖性要求. 离线安装文件地址: ht ...

  5. 使用Gitlab的CI/CD功能自动化推送docker镜像到Nexus仓库出现的问题

    在服务器中可以直接使用命令行登录,推送docker镜像等 但是在使用Gitlab的CI/CD功能中,gitlab-ci.yml文件执行过程中出现如下错误: 原因分析: 服务器上之前使用命令行登陆过Ne ...

  6. HDU2041 超级楼梯 (线性DP)

    fn[i]表示走上第i级台阶的所有走法. 方程:fn[i]=fn[i-1]+fn[i-2]; 1 #include<cstdio> 2 #define MAXN 40 3 using na ...

  7. 实例分析Scheduled Thread Pool Executor与Timer的区别

    摘要:JDK 1.5开始提供Scheduled Thread PoolExecutor类,Scheduled Thread Pool Executor类继承Thread Pool Executor类重 ...

  8. 第一个java程序进行总结

    1.java程序编写-编译-运行的过程 编写:我们将编写的java代码保存在以".java"结尾的源文件中 编译:使用javac.exe命令编译我们的java源文件.格式:java ...

  9. 驱动开发:内核枚举ShadowSSDT基址

    在笔者上一篇文章<驱动开发:Win10枚举完整SSDT地址表>实现了针对SSDT表的枚举功能,本章继续实现对SSSDT表的枚举,ShadowSSDT中文名影子系统服务描述表,SSSDT其主 ...

  10. 我要手撕mybatis源码

    传统的JDBC编程中的一般操作: 1.注册数据库驱动类,指定数据库的URL地址.数据库用户名.密码等连接信息 2.通过DriverManager打开数据库连接 3.通过数据库连接创建Statement ...