网站建设与管理 管理课程,企业信用信息查询公示系统天津,网站开发 方案 报价,足球网站网站建设文章目录 前言正文(1) 三种智能指针(2) 智能指针的设计思路(3) unique_ptrunique_ptr的几种初始化方法获取unique_ptr的地址unique_ptr的使用 (4) shared_ptr 前言
一般来说#xff0c;我们想要在堆上开辟内存空间需要使用关键字new#xff0c;但由于使用new之后我们还是需要… 文章目录 前言正文(1) 三种智能指针(2) 智能指针的设计思路(3) unique_ptrunique_ptr的几种初始化方法获取unique_ptr的地址unique_ptr的使用 (4) shared_ptr 前言
一般来说我们想要在堆上开辟内存空间需要使用关键字new但由于使用new之后我们还是需要进行手动释放我们却常常忘记delete或者在不该delete的地方delete了这就会导致程序出错。 因此C11推出了智能指针让程序管理内存让程序对new出来的内存进行自动释放在析构智能指针的时候同时delete对象这样就能避免很多因为粗心产生的bug。
正文
(1) 三种智能指针
这三种智能指针都在头文件memory中
unsigned_ptr可以有多个指针指向同一个对象其中包含了一个计数器unique_ptr独占指向的对象weak_ptr指向shared_ptr所管理的对象
(2) 智能指针的设计思路
智能指针是类模板在栈上创建智能指针对象将普通指针交给智能指针对象智能指针对象过期时调用析构函数释放普通指针的内存
其实还有个auto_ptr但是在C17中移除了这里也就不说了
(3) unique_ptr
它的意思是独享也就是一个unique_ptr对象只对一个资源负责当它析构的时候指向的对象所分配的内存也随之释放。 因此它在定义的时候禁用了拷贝构造函数和复制构造函数。
unique_ptr operator( const unique_ptr ) delete;
constexpr unique_ptr( std::nullptr_t ) noexcept delete;但是我们需要注意指针和智能指针是两种类型因此我们不能直接使用智能指针接收new出来的对象
#includeiostream
#includememoryint main(){// 正确std::unique_ptrint ptr(new int(5));// 正确C14的写法std::unique_ptrint ptr2 std::make_ptrint(int(5));// 错误不能直接使用智能指针接收直接new出来的对象std::unique_ptrint ptr3 new int(10);// 错误拷贝构造函数是已被删除的函数// 在VS中会显示该函数已被删除std::unique_ptrint temp_ptr(ptr);
}
它的底层原理其实也很简单他的内部只有一个指针这个指针指向的是它初始化时所指定的对象。 这里写一段示例代码
#include iostream
#include ostream
#include memoryclass AA{
public:// 利用友元进行运算符重载friend std::ostream operator(std::ostream os, const AA temp);AA(){this-val 0;std::cout 调用了AA的构造函数 std::endl;}AA(const int value){std::cout 调用了AA的初始化构造函数 std::endl;this-val std::move(value); }~AA(){std::cout 调用了AA的析构函数 std::endl;}int showVal() const{return this-val;}private:int val;
};// 需要注意ostream是命名空间std的成员
// 并且我上面没有手动使用std::
// 需要注意的点被const声明的变量只能使用const声明的成员函数
std::ostream operator(std::ostream os, const AA temp){os temp.showVal();return os;}int main(){AA* temp new AA(100);std::cout *temp std::endl;std::unique_ptrAA auto_ptr(temp);std::cout main函数运行中 std::endl;
}通过输出语句的顺序我们就能够理解它的原理
调用了AA的初始化构造函数
100
main函数运行中
调用了AA的析构函数它其实就是在智能指针进行析构的时候其析构函数中再调用了其所指向对象的析构函以此来释放所分配的内存。 智能指针重载了输入输出运算符因此我们可以像使用普通指针一样去使用智能指针。 这里需要注意一个问题不要用同一个指针也叫裸指针或者原始指针去初始化不同的unique_ptr对象。这个原因也很简单就是重复释放内存的跟深浅拷贝一样。
unique_ptr的几种初始化方法
这里我就直接给出代码吧
#include memory
using namespace std;
int main(){unique_ptrint ptr1(new int(100)); // 分配内存并初始化unique_ptrint ptr2 make_uniqueint(100); // C14标准int temp 100;unique_ptrint ptr3(temp); // 用已存在的地址初始化
}获取unique_ptr的地址
在C20之前unique_ptr没有重载输出运算符所以我们不能像使用普通指针那样输出智能指针所指向的地址
#include memory
#include iostream
int main(){std::unique_ptrint ptr(new int(5));// 错误unique_ptr不支持输出运算符std::cout ptr;
}想要获取其指向的地址需要使用其成员函数get()
#include memory
#include iostream
int main(){std::unique_ptrint ptr(new int(5));// 错误unique_ptr不支持输出运算符std::cout ptr.get() std::endl;std::cout *ptr std::endl;
}由于智能指针为了模拟原始指针而重载了*“运算符和”-运算符因此我们能够像原始指针一样去使用它。
unique_ptr的使用
这里需要重点强调的是unique_ptr作为参数进行函数传递的时候我们都知道函数传参有两种方式值传递和引用传递。 前面我们说到由于unique_ptr是独享的因此它禁用了拷贝构造函数和复制构造函数正是因此unique_ptr在作为参数传递的时候只能使用引用传递
#include memory
#include iostreamvoid func(std::unique_ptrint ptr){std::cout ptr.get() 中存储的数据是 *ptr std::endl;
}int main(){std::unique_ptrint ptr std::make_uniqueint(100);func(ptr);
}上面这段函数会报错正式因为使用的是值传递只需要将函数传参变为传引用即可
void func(std::unique_ptrint ptr){}(4) shared_ptr
std::shared_ptr底层和std::unique_ptr差不多但它底层增加了一个计数器用于计算共有多少个shared_ptr共享同一个对象
#include memory
#include iostream
int main(){std::shared_ptrint ptr std::make_sharedint(5);std::cout ptr ptr.get() std::endl;std::cout 共有 ptr.use_count() 个shared_ptr指向 ptr std::endl;std::shared_ptrint ptr2 ptr1;std::cout 共有 ptr.use_count() 个shared_ptr指向 ptr std::endl;
}知道了unique_ptrshared_ptr就很好理解了。 现在我们来看看shared_ptr的常用方法
get()和unique_ptr中的一样获取指向底部管理着的对象的地址use_count()获取当前shared_ptr中的计数器