一、简介
是一种抽象类型,由类模板来实现,借由类别的析构函数来达到自动释放指针所指向的存储器或对象;
二、四种智能指针
1、auto_ptr
该智能指针管理通过new 创建auto_ptr获得的对象,并在其自身被销毁时删除该对象 ;
注意
- 不可用多个指向
同一个对象 ,当使用拷贝构造 或赋值运算符 时,右值会变为nullptr ; - 在C++11被弃用,C++17被删除;
2、unique_ptr
template<
class T,
class Deleter = std::default_delete<T>
> class unique_ptr;
通过指针拥有和管理对象,且对该对象具有唯一权,没有其他操作能删除该对象;
- 该智能指针禁止
拷贝 和赋值 操作,但可通过std::move 移动赋值; - 可通过reset进行更改;
- 对于数组对象提供
[] 运算符;
关于为何对接管对象具有唯一权
由于当该对象被删除时,若有其他指针托管该对象,则其他的指针将会无效;
2.1 测试案例
#include <iostream>
#include <memory>
#include <string>
using namespace std;
class A{
public:
A(int a) : m_a(a) {
cout << "A..." << endl;
}
~A() {
cout << "Bye..." << endl;
}
int getA() const {
return m_a;
}
private:
int m_a;
};
创建
void test_unique_ptr() {
std::unique_ptr<A> u_a(new A(1));
std::unique_ptr<A> u_b;
u_b.reset(new A(2));
std::unique_ptr<A> u_c = std::make_unique<A>(3);
cout << "u_a: " << u_a->getA() << endl;
cout << "u_b: " << u_b->getA() << endl;
cout << "u_c: " << u_c->getA() << endl;
std::unique_ptr<A> u_d = std::move(u_c);
cout << "u_d : " << u_d ->getA() << endl;
}
reset
void test_unique_ptr() {
std::unique_ptr<A> u_b(new A(2));
u_b.reset(new A(4));
cout << "u_b: " << u_b->getA() << endl;
}
3、weak_ptr
template <class T> class weak_ptr;
弱管理对象的类型,提供了对其管理的资源的一个访问手段 ,为协助shared_ptr ;
- 析构和构造不会造成计数的增加或减少;
- 可以解决两个shared_ptr互相引用造成的死锁问题,导致资源不会释放;
- 该智能指针没有重载
* 以及-> ,故不能直接操作对象,由于可能在操作的时候该对象被释放而引发错误;
3.1 提供的成员函数
operator=
- 不会获得所有权,且不会增加计数;
- shared_ptr可以直接分配给
weak_ptr ; - 当一个
weak_ptr 分配给shared_ptr 需要使用lock 来完成;
void test_weak_ptr(){
std::shared_ptr<A> ptr1(new A(1));
std::shared_ptr<A> ptr2;
std::weak_ptr<A> wptr;
wptr = ptr1;
ptr2 = wptr.lock();
cout << "ptr1:" << &(*ptr1) << endl;
cout << "ptr2:" << &(*ptr2) << endl;
}
swap
交换对象;
void test_weak_ptr(){
std::shared_ptr<A> ptr1(new A(1));
std::shared_ptr<A> ptr2(new A(2));
std::weak_ptr<A> wptr1 = ptr1;
std::weak_ptr<A> wptr2 = ptr2;
wptr1.swap(wptr2);
cout << "ptr1: " << &(*ptr1) << endl;
cout << "ptr2: " << &(*ptr2) << endl;
cout << "wptr1: " << &(*wptr1.lock()) << endl;
cout << "wptr2: " << &(*wptr2.lock()) << endl;
}
reset
重置变为空;
void test_weak_ptr(){
std::shared_ptr<A> ptr1(new A(1));
std::weak_ptr<A> wptr1 = ptr1;
wptr1.reset();
std::cout << "wptr1 " << (wptr1.expired() ? "" : "没有") << " 过期\n";
}
use_count
共享所有权的shared_ptr对象的数量 ;
expired
lock
若未过期,返回一个shared_ptr,包含由weak_ptr对象保留的信息;
3.2 应用场景
- 辅助shared_ptr的使用;
- 出现于该资源能使用则使用,不能使用则不用;
4、shared_ptr
template <class T> class shared_ptr;
对象具有获得指针所有权并共享该所有权的能力,持有的资源能在多个shared_ptr之间共享;
- 当多一次对该对象的引用,则引用计数加一,若发生析构,则减一;
- 当引用计数为0时,则释放该资源;
4.1 常用成员函数
operator=
- 复制:使该对象的引用计数加1;
- 移动:则原对象将变为空;
void test_shared_ptr() {
std::shared_ptr<A> ptr1(new A(1));
std::shared_ptr<A> ptr2;
cout << "ptr1:" << ptr1.use_count() << endl;
cout << "ptr2:" << ptr2.use_count() << endl;
ptr2 = ptr1;
cout << "ptr1:" << ptr1.use_count() << endl;
cout << "ptr2:" << ptr2.use_count() << endl;
ptr2 = std::make_shared<A>(2);
cout << "ptr1:" << ptr1.use_count() << endl;
cout << "ptr2:" << ptr2.use_count() << endl;
}
swap
交换托管对象内容,不会破坏或更改引用计数;
void test_shared_ptr() {
std::shared_ptr<A> ptr1(new A(1));
std::shared_ptr<A> ptr2(new A(2));
ptr1.swap(ptr2);
cout << "ptr1引用计数: " << ptr1.use_count() << endl;
cout << "ptr2引用计数: " << ptr2.use_count() << endl;
}
reset
重置指针,若原先由托管,则会将原先的删除;
- 若不传入参数,则原对象的引用计数会减一;
- 若传入参数,则该对象的引用计数会加一;
void test_shared_ptr() {
std::shared_ptr<A> ptr1(new A(1));
ptr1.reset();
cout << "ptr1引用计数: " << ptr1.use_count() << endl;
ptr1.reset(new A(2));
cout << "ptr1引用计数: " << ptr1.use_count() << endl;
}
get
获取指针;
void test_shared_ptr() {
A *a = new A(2);
std::shared_ptr<A> ptr1(a);
cout << "ptr1:" << ptr1.use_count() << endl;
if (a == ptr1.get()) {
cout << "equal..." << endl;
}
}
operator*
取消引用对象;
void test_shared_ptr() {
A *a = new A(2);
std::shared_ptr<A> ptr1(a);
cout << "ptr1:" << ptr1.use_count() << endl;
if (a == ptr1.get()) {
cout << "equal..." << endl;
}
if (&(*ptr1) == a){
cout << "equal..." << endl;
}
}
operator->
取消引用对象成员,即直接调用对象成员;
void test_shared_ptr() {
A *a = new A(2);
std::shared_ptr<A> ptr1(a);
cout << a->getA() << endl;
}
use_count
获取引用计数;
unique
检查是否唯一;
operator bool
检查是否不为空;
operators ==, !=, <, <=, >, >=
重载了运算符;
operator<<
make_shared
制作shared_ptr;
4.2 引用计数
当计数器为0 时,智能指针将会自动释放 ;
何时计数器会递增
- 当使用拷贝时
shared_ptr<T> p(q) p时q的拷贝,计数器会递增; - 当两个智能指针相互转换时,
左边 的指针对象会增加 ; - 当它作为参数传递时;
- 当它作为函数返回值时;
何时计数器会递减
- 当两个智能指针
相互转换 时,右边的指针对象会递减 ; - 当智能指针被销毁时;
使用new返回的指针来初始化智能指针;
- 一般初始化智能指针的指针必须指向动态内存;
- 由于之智能指针内部的构造函数是
explicit ,不能进行隐式转换,必须使用直接初始化 ; - 由于不清楚对象何时销毁,则最好不使用内置指针来访问一个智能指针且不使用
get() 初始化或赋值;
shared_ptr<T> p(new T(1));
4.3 share_ptr与new结合使用
当new与share_ptr作为参数时
int func();
void test(std::shared_ptr<int> p, int func);
由于智能指针内部的构造函数是explicit ,故不能直接传入new 创建的指针;
test(std::shared_ptr<int> (new int), func());
第一个参数被分为俩部分:std::shared_ptr<int> 与new int ; 由于编译器考虑高效的操作,故传入参数的执行顺序:
- 执行
new int ; - 调用
func ; - 调用
智能指针构造 ;
但需要考虑到,万一func 函数内部出现异常,则此时将会引起内存泄漏,由于new int 返回的指针遗失;
故将实参一先单独出来:
std::shared_ptr<int> p(new int);
test(p, func());
4.4 enable_shared_from_this
在子类中继承该类,能够让子类的对象创建指向自身的shared_ptr实例;
class A : enable_shared_from_this<A>{
public:
A(int a) : m_a(a) {
cout << "A..." << endl;
}
~A() {
cout << "Bye..." << endl;
}
shared_ptr<A> GetThis() {
return shared_from_this();
}
int getA() const {
return m_a;
}
private:
int m_a;
};
void test_shared_ptr() {
std::shared_ptr<A> ptr(new A(1));
auto p = ptr->GetThis();
cout << ptr.use_count() << endl;
}
注意事项
- 不能将栈对象,来获取
shared_from_this ,会导致程序奔溃;
void test_shared_ptr() {
A a(1);
auto p = a.GetThis();
}
5、注意事项
- 分清楚什么情况下使用哪一种指针:
- 当该资源只用在当前且不共享的情况下,使用
unique_ptr ; - 当智能指针不需要管理对象的生命周期下,使用
weak_ptr ; - 若要其他地方共享使用,使用
shared_ptr ; - 注意使用时,该资源是否
有效 ; - 作为类成员的时,一般优先考虑
向前声明 ,而不是作为头文件导入;
|