智能指针
智能指针是RAII(Resource Acquisition Is Initialization,资源获取即初始化)机制对普通指针进行的一层封装。这样使得智能指针的行为动作像一个指针,本质上却是一个对象,这样可以方便管理一个对象的生命周期。在c++中,智能指针一共定义了4种:
auto_ptr、unique_ptr、shared_ptr 和 weak_ptr。其中,auto_ptr 在 C++11已被摒弃,在C++17中已经移除不可用。
智能指针能对堆区声明的内存自动释放,保证了内存管理的安全,不会出现野指针,使用智能指针需要添加头文件
#include <memory>
1.unique_ptr
不允许进行拷贝,只允许一个unique_ptr对象持有指针,因为多个unique_ptr对象持有同一个指针时,会对该指针指向的内存多次释放
unique_ptr的初始化方式
std::unique_ptr<int> valuePtr(new int(47));
也可以使用默认构造函数,再使用reset方法重新设置指针,注:如果使用reset方法之前unique_ptr对象本身就有指针,那么会先将原有指针释放掉,再设置新的指针
std::unique_ptr<int> valuePtr;
valuePtr.reset(new int(47));
unique_ptr支持移动语义,可以将一个unique_ptr对象所持有的指针复制给另一个对象
#include <iostream>
#include <memory>
#include <utility>
int main()
{
std::unique_ptr<int> valuePtr(new int(15));
std::unique_ptr<int> valuePtrNow(std::move(valuePtr));
std::cout << "valuePtrNow = " << *valuePtrNow << '\n';
std::cout << "Has valuePtr an associated object? "
<< std::boolalpha
<< static_cast<bool>(valuePtr) << '\n';
}
代码输出为
valuePtrNow = 15
Has valuePtr an associated object? false
2.shared_ptr
shared_ptr是一种引用计数指针,当引用计数为零时,会自动对指针所指向的内存进行释放,可以进行函数间的引用传递。这一特性可以用于基于类和对象编程中,存储一个类成员变量的指针并将其引用传递到类之外使用
#include <memory>
class Foo
{
public void doSomething();
};
class Bar
{
private:
std::shared_ptr<Foo> pFoo;
public:
Bar()
{
pFoo = std::shared_ptr<Foo>(new Foo());
}
std::shared_ptr<Foo> getFoo()
{
return pFoo;
}
};
在上面的代码中,创建一个Bar对象会创建一个Foo对象的指针,存储在Bar对象的私有成员变量中,可以通过Bar的getFoo方法获取该指针,getFoo方法中会调用std::shared_ptr 的拷贝构造函数创建一个Foo对象的引用并将计数加一,下面调用这个类
void SomeAction()
{
Bar* pBar = new Bar(); //with the Bar object, a new Foo is created and stored
//reference counter = 1
std::shared_ptr<Foo> pFoo = pBar->getFoo(); //a copy of the shared pointer is created
//reference counter = 2
pFoo->doSomething();
delete pBar; //with pBar the private pFoo is destroyed
//reference counter = 1
return; //with the return the local pFoo is destroyed automatically
//reference counter = 0
//internally the std::shared_ptr destroys the reference to the Foo object
}
我们无需手动删除pFoo,简化了内存管理
void SomeOtherAction(std::shared_ptr<Bar> pBar)
{
std::shared_ptr<Foo> pFoo = pBar->getFoo(); //a copy of the shared pointer is created
//reference counter = 2
pFoo->doSomething();
return; //local pFoo is destroyed
//reference counter = 1
}
函数返回后,pBar被删除,但是还是会保留一个引用
循环引用问题
shared_ptr最大的坑就是循环引用。引用网络上的一个例子:
循环引用: link
3.weak_ptr
C++11标准虽然将weak_ptr定位为智能指针的一种,但该类型指针通常不单独使用(实际没有用处),只能和shared_ptr类型指针搭配使用。甚至于,我们可以将weak_ptr类型指针视为shared_ptr指针的一种辅助工具,借助weak_ptr类型指针,我们可以获取shared_ptr指针的一些状态信息,比如有多少指向相同的shared_ptr指针,shared_ptr指针指向的堆内存是否已经被释放等等。
需要注意的是,当weak_ptr类型指针的指向和某一shared_ptr指针相同时,weak_ptr指针并不会使所指堆内存的引用计数加1;同样,当weak_ptr指针被释放时,之前所指堆内存的引用计数也不会因此而减1。也就是说,weak_ptr类型指针并不会影响所指堆内存空间的引用计数。
除此之外,weak_ptr模板类中没有重载*和->运算符,这也就意味着,weak_ptr类型指针只能访问所指的堆内存,而无法修改它。
成员方法 | 功能 |
---|---|
operator=() | 重载=赋值运算符,weak_ptr指针可以直接被weak_ptr或者shared_ptr类型指针赋值 |
swap(x) | 其中x表示一个同类型的weak_ptr类型指针,该函数可以互换2个共同类型weak_ptr指针的内容 |
reset() | 将当前weak_ptr指针置为空指针 |
use_count() | 查看指向和当前weak_ptr指针相同的shared_ptr指针的数量 |
expired() | 判断当前weak_ptr指针是否过期(指针为空,或者指向的堆内存已经被释放) |
lock() | 如果当前weak_ptr已经过期,则该函数会返回一个空的shared_ptr指针;反之,该函数返回一个和当前weak_ptr指针指向相同的shared_ptr指针。 |
使用smart_ ptr允许我们传递和返回对对象的引用,而不会出现内存泄漏或访问已删除引用的无效尝试。因此,它们是现代内存管理的基石。
参考:
https://en.cppreference.com/book/intro/smart_pointers
https://blog.csdn.net/bitcarmanlee/article/details/124847634