我们知道在c++中,内存有五个区:堆区,栈区,自由存储区,全局/静态存储区和常量存储区。
栈区:就是通常由编译器在需要的时候进行分配,在不需要的时候自动清除的区域,比如局部变量,函数参数。
堆区:就是那些由new出来的分配的内存块,它们的释放编译器不用管,是由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么程序再结束时由系统进行回收。
自由存储区:它和堆是十分类似的。不过它是由free来结束自己的。
全局/静态存储区:全局变量和静态变量是存储在同一内存中的。在以前的c语言中,全局变量区分初始化和未初始化的。现在在c++中没有这个区分。
常量存储区:这是一块特殊的存储区,它存储的是常量。
那么对于堆区,我们经常会使用new/delete。但是有时确实经常忘了使用delete会造成内存泄漏。还有就是在还有引用使用的时候就去释放它,往往会造成内存泄漏。
这时候,为了安全的使用指针,智能指针,它来了。
它和常规指针类似,但是它会自动地释放所指向的内存。
标准库提供的两种智能指针的区别在于底层管理指针的方式不同。
shared_ptr运行多个指针指向同一个对象。
unique_ptr则独占所指向的对象。
weak_ptr它是一种弱引用,它指向shared_ptr所指向的对象。
这三种智能指针都存放在memory中。
下面进行这三种指针的分别介绍:
1、shared_ptr:
它是c++11(原来存在于boost中)提供的一个智能指针,由于它足够智能,所以可以在任何地方都不使用时自动删除使用。
从而彻底消除因其导致内存泄漏和悬空指针的问题。
并且它遵循共享所有权的概念,即不同的shared_ptr对象可以与相同的指针想关联。并在内部使用引用计数机制来实现这一点。
每个shared_ptr在内部指向两个内存地点:
a、指向对象的指针。
b、用于控制引用计数数据的指针。
共享所有权如何在引用计数的机制下进行工作:
当有shared_ptr的对象与指针进行关联时,则在其构造函数中,将与此关联的引用加1。
当任何shared_ptr超出作用域时,则在其析构函数中,与此关联的引用见一个。
当引用计数为0时,则说明没有与其关联的对象。这种情况下,它会delete删除该内存。
比如创建shared_ptr对象:
std::shared_ptr<int> p1(new int());
这段代码在堆上创建了两段内存:1、存储int。2、用于引用计数的存储的内存。
检查引用计数可以用p1.use_count();
再比如:创建空的shared_ptr对象:
std::shared_ptr<int> p1=std::make_shared<int>();
std::make_shared一次性为int和引用计数都分配了内存。
要使shared_ptr取消与相关指针的关联。可以使用reset()函数。
p1.reset();此时引用计数为减1。
p1.reset(new int(34));使用带参数的reset()函数。因此其引用计数将再次变为1,因为它将在内部指向新指针。
2、unique_ptr:
与shared_ptr不同的是,它是一个独享所有权的智能指针。
无法进行复制构造,赋值构造,只能进行移动操作。无法使两个相同的unique_str指向同一个对象。
unique_ptr 它只能智能的指向一个对象,如果当它能够指向其他对象时,之前所指向的对象会被销毁。
unique_ptr对象会在它们自身被销毁时,使用删除器删除它们管理的对象。
unique_ptr支持数组创建方法。
3、weak_ptr:
它是一种不控制对象生命周期的智能指针,它指向一个shared_ptr管理的对象。进行该对象的内存管理的是强引用的
shared_ptr。weak_ptr只是提供了对管理对象的一个访问手段.,
weak_ptr 设计的目的是为配合 shared_ptr 而引入的一种智能指针来协助 shared_ptr 工作, 它只可以从一个 shared_ptr 或另一个 weak_ptr 对象构造, 它的构造和析构不会引起引用记数的增加或减少. 。