使用智能指针首先要引用头文件
#include<memory>
内存泄漏
shared_ptr是用来解决c++中内存泄漏的问题
什么是内存泄漏呢
内存泄漏
内存泄漏就是我们从堆区申请的一块空间,没有对这块空间进行释放,导致这块空间既不能被重新利用,也不能被找到。
什么会导致内存内存呢
未释放动态分配的内存
shared_ptr循环引用,引用计数可能永远不会降为0.
虚析构,在继承关系中,编译器会把基类与派生类的构造函数同名,此时析构函数为函数隐藏,只会调用指针类型里的析构函数发生内存泄漏。
内存泄漏会导致很多问题,比如长时间运行,性能变差,程序莫名被挂掉,越界等问题
怎么解决内存泄漏的问题
- 使用智能指针,shared_ptr,unique_ptr,可以在对象生命周期结束自动释放
- RAII思想,RAII指的就是确保资源在对象构造的时候获得,被析构掉的时候自动释放资源。
- 使用工具检测内存泄漏,Valgrind,cppcheck等检测工具。
内存泄漏如何定位
- 静态的分析工具,cppcheck,可以在编译阶段检测一些潜在的内存泄漏问题
- 动态分析工具,Valgrind在Linux系统上较为常用,
- 编写自定义的内存分析器
shared_ptr
shared_ptr是一种引用计数思想,当多个指针指向同一对象的时候,这时候对象的引用计数加一,当对象的引用计数为0的时候说明,没有指针再指向这块内存了,我们就要把这块内存释放掉。
实现shared_ptr
#include<iostream>
#include<memory>
using namespace std;
template<class T>
//实现智能指针
/*
无参构造:传递指针构造,拷贝构造,移动构造,移动赋值
reset()替换对象,销毁对象
operator*()
get()获取原始指针
use_count获得引用计数
*/
class Ref {
int r_count = 0;
T* obj = nullptr;
public:
Ref():{}
Ref(T* target) :obj(target) {
r_count++;
}
//引用计数加1
inline void increase() {
r_count++;
}
//引用计数减一
inline vopid reduce() {
r_count--;
if (r_count == 0) {
delete obj;
delete this;
}
}
T* get() {
return obj;
}
int getCount() {
return r_count;
}
};
template<class T>
class Shared_ptr {
Ref<T>* ref = nullptr;
public:
Shared_ptr() = default;
~Shared_ptr() {
if (ref)ref->reduce();
}
Shared_ptr(T* newP) {
cout << "构造函数---------" << endl;
ref = new Ref<T>(newP);
}
Shared_ptr(const Shared_ptr& other) {
cout << "拷贝构造函数---------" << endl;
this->ref = other.ref;
if (ref)ref->increase();
}
Shared_ptr(Shared_ptr&&other) {
cout << "移动构造---------" << endl;
ref = other.ref;
other.ref = nullptr;
}
//给已经存在的对象赋值
Shared_ptr& operator=(const Shared_ptr& other) {
cout << "赋值函数---------" << endl;
if (ref) {
ref->reduce();
}
ref = other.ref;
if (ref) {
ref->increase();
}
return *this;
}
Shared_ptr& operator=(Shared_ptr&& other) {
cout << "移动赋值---------" << endl;
if (ref) {
ref->reduce();
}
ref = other.ref;
other.ref = nullptr;
return *this;
}
void reset(T*target) {
if (ref)ref->reduce();
ref = neww Ref<T>(target);
}
void reset() {
if (ref)ref->reduce();
ref = nullptr;
}
T& operator*() {
return *ref->get();
}
T* operator->() {
if (ref) {
return ref->get();
}
}
int user_count() {
if (ref)return ref->getCount();
else return 0;
}
};
weak_ptr
weak_ptr指针指向对象的时候,并不会导致对象的引用计数加一,因为weak_ptr是用来检测当前对象的引用计数为多少,用他来获取shared_ptr中的一些信息。查看shared_ptr指向的堆区内存是否被释放掉
weak_ptr用来解决shared_ptr多个对象之间交叉有对方类型的引用,导致引用计数可能永远不会为0的循环引用问题
通常不单独使用,只能和shared_ptr联合使用,
unique_ptr
独享所有权的智能指针,提供了严格意义上的所有权
当该对象被销毁时,会在其析构函数中删除关联的原始指针。