代码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. Go工程化 - 依赖注入

    我们在微服务框架kratos v2的默认项目模板中kratos-layout使用了google/wire进行依赖注入,也建议开发者在维护项目时使用该工具. wire 乍看起来比较违反直觉,导致很多同学 ...

  2. 安装 Helm3 管理 Kubernetes 应用

    文章转载自:http://www.mydlq.club/article/51/ 系统环境: Helm 版本:v3.5.0 Kubernetes 版本:v1.18.2 一.Helm 介绍 Helm 是一 ...

  3. 请求体: Request Body

    官方文档地址:https://fastapi.tiangolo.com/zh/tutorial/body/ # -*- coding: UTF-8 -*- from fastapi import Fa ...

  4. Django环境安装

    1.安装Django # 自动安装PyPi提供的最新版本 pip install django # 安装指定版本 pip install django==2.2 # 验证安装 >>> ...

  5. 从Spring Cloud微服务视角理解Kubernetes

  6. useContext 解决函数父子组件传值

    1在父组件外部定义变量A创建上下文,2在父组件使用变量A<A.Provider> <子组件/> </A.Provider> ,3.在子组件中创建变量使用useCon ...

  7. 1_Maven

    一. 引言 1.1 项目管理问题 项目中jar包资源越来越多, jar包的管理越来越沉重 1.1.1 繁琐 要为每个项目手动导入所需的jar, 需要搜集全部的jar 1.1.2 复杂 项目中的jar如 ...

  8. Java问题之超过数值表示范围(例如64位)结果是什么 (阶乘)

    关于老师在课上所提及的这个问题 我做了验证 截图如下 只是一个简单的计算阶乘的代码 在运行时得到了如下结果 可以看到,对于部分数字如果超出范围会从64位处自动截断,而这时由于是二进制表示,首位默认是符 ...

  9. POJ2533 Longest Ordered Subsequence (线性DP)

    设dp[i]表示以i结尾的最长上升子序列的长度. dp[i]=max(dp[i],dp[j]+1). 1 #include <map> 2 #include <set> 3 # ...

  10. ubuntu安装及使用

    ubuntu教程 一. Ubuntu简介 Ubuntu(乌班图)是一个基于Debian的以桌面应用为主的Linux操作系统,据说其名称来自非洲南部祖鲁语或科萨语的"ubuntu"一 ...