一、简介
二、四种智能指针
- 1、auto_ptr
- 2、unique_ptr
- 2.1 测试案例
- 3、weak_ptr
- 3.1 提供的成员函数
- 3.2 应用场景
- 4、shared_ptr
- 4.1 常用成员函数
- 4.2 引用计数
- 4.3 share_ptr与new结合使用
- 4.4 enable_shared_from_this
- 5、注意事项
一、简介
是一种抽象类型,由类模板来实现,借由类别的析构函数来达到自动释放指针所指向的存储器或对象;
- 支持自动、异常安全的对象生命周期管理;
二、四种智能指针 1、auto_ptr
该智能指针管理通过
new
创建auto_ptr获得的对象,并在其自身被销毁时删除该对象
;
注意
2、unique_ptr
- 不可用多个指向
同一个对象
,当使用拷贝构造
或赋值运算符
时,右值会变为nullptr
;- 在C++11被弃用,C++17被删除;
template<
class T,
class Deleter = std::default_delete<T>
> class unique_ptr;
通过指针拥有和管理对象,且对该对象具有唯一权,没有其他 *** 作能删除该对象;
- 该智能指针禁止
拷贝
和赋值
*** 作,但可通过std::move
移动赋值;- 可通过reset进行更改;
- 对于数组对象提供
[]
运算符;
关于为何对接管对象具有唯一权
2.1 测试案例由于当该对象被删除时,若有其他指针托管该对象,则其他的指针将会无效;
#include
#include
#include
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() {
// 方式1
std::unique_ptr<A> u_a(new A(1));
// 方式2
std::unique_ptr<A> u_b;
u_b.reset(new A(2));
// 方式3
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::move
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;
3.1 提供的成员函数弱管理对象的类型,提供了对其管理的资源的一个
访问手段
,为协助shared_ptr
;
- 析构和构造不会造成计数的增加或减少;
- 可以解决两个shared_ptr互相引用造成的死锁问题,导致资源不会释放;
- 该智能指针没有重载
*
以及->
,故不能直接 *** 作对象,由于可能在 *** 作的时候该对象被释放而引发错误;
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;
// 将shared_ptr转换为weak_ptr
wptr = ptr1;
// 将weak_ptr转换为shared_ptr
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对象的
数量
;
weak_ptr
不计算在内;
expired
- 检查是否过期, weak_ptr对象是否为空;
lock
3.2 应用场景若未过期,返回一个shared_ptr,包含由weak_ptr对象保留的信息;
4、shared_ptr
- 辅助shared_ptr的使用;
- 出现于该资源能使用则使用,不能使用则不用;
template <class T> class shared_ptr;
4.1 常用成员函数对象具有获得指针所有权并共享该所有权的能力,持有的资源能在多个shared_ptr之间共享;
- 当多一次对该对象的引用,则引用计数加一,若发生析构,则减一;
- 当引用计数为0时,则释放该资源;
operator=
- 复制:使该对象的引用计数加1;
- 移动:则原对象将变为空;
void test_shared_ptr() {
std::shared_ptr<A> ptr1(new A(1));
std::shared_ptr<A> ptr2;
// copy
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;
// move
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
4.2 引用计数制作shared_ptr;
当计数器为
0
时,智能指针将会自动释放
;
何时计数器会递增
- 当使用拷贝时
shared_ptr
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
与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
;- 注意使用时,该资源是否
有效
;- 作为类成员的时,一般优先考虑
向前声明
,而不是作为头文件导入;
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)