智能指针之atuo_ptr源码剖析
Posted xcb-1024day
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了智能指针之atuo_ptr源码剖析相关的知识,希望对你有一定的参考价值。
由于c++没有垃圾回收机制,像堆只能手动开辟内存,手动释放,像栈只能系统开辟,系统释放,于是智能指针出现了,它实现了内存的手动开辟,系统释放,防止了内存泄漏问题;
我们知道, 栈对象在离开其作用域的时候, 会自动调用析构函数, 所以, 可以考虑把某一栈对象与某一堆内存绑定,且在其析构函数中释放堆内存, 那么, 在该栈对象离开作用域时, 堆内存自动释放, 这就是智能指针(本质是栈对象)的原理。 这个栈对象装得像指针一样, 所以我们称之为智能指针, 其实, 它不过就是个普通的栈对象而已。
在c++ 98 中只有auto-ptr,这个指针是不完善的,现在几乎都要被摒弃了,但我们还是要去了解一下他的思想,明白为何要被摒弃的呢?以及在c++11上又是如何对他如何改进的呢?
//自动指针即auto_ptr,不同于scoped_ptr指针的是自动指针会转移使用权
//在进行赋值或者拷贝构造之后,原来的auto_ptr会失去对所管指针的拥有权,并且将自己的指针赋为NULL
//同时,在赋值和拷贝构造之后,原来的auto_ptr的指针会指向NULL,也是它最大的弊端之一;
#include <iostream>
using namespace std;
// 简单类
class A
public:
void fun()
;
template<class T>
// 类模板
class auto_ptr
public:
// explicit构造函数, 禁止类型转化
explicit auto_ptr(T *p = 0) throw()
: m_bIsOwner(p != 0), m_ptr(p)
cout << "debug1" << endl;
// owner转移
auto_ptr(const auto_ptr<T>& y) throw()
: m_bIsOwner(y.m_bIsOwner), m_ptr(y.release())
cout << "debug2" << endl;
// owner转移
auto_ptr<T>& operator=(const auto_ptr<T>& y) throw()
cout << "debug3" << endl;
if (this != &y) // 当前对象不是y对象
cout << "debug4" << endl;
if (m_ptr != y.get()) // 当前对象绑定的地址不是y对象绑定的地址
cout << "debug5" << endl;
if (m_bIsOwner) // 如果当前对象已经绑定堆, 则要先释放
cout << "debug6" << endl;
delete m_ptr;
cout << "debug7" << endl;
m_bIsOwner = y.m_bIsOwner; // 转移owner
else if (y.m_bIsOwner) // 当前对象与y绑定到同一块堆上, 且y是owner, 则把y的owner转移给当前对象
cout << "debug8" << endl;
m_bIsOwner = true;
cout << "debug9" << endl;
m_ptr = y.release(); // 让y不再是owner
cout << "debug10" << endl;
return *this; // 返回当前对象的引用
// 析构函数
~auto_ptr()
cout << "debug11" << endl;
if (m_bIsOwner) // 只有拥有owner属性才释放堆, 这样避免重复释放
cout << "debug12" << endl;
delete m_ptr; // 即使m_ptr是空指针也木有关系
// 重载对象的*运算符, 使得对象"看起来"像指针, 可以执行*p操作
T& operator*() const throw()
cout << "debug13" << endl;
return *get();
// 重载对象的->运算符
T *operator->() const throw()
cout << "debug14" << endl;
return get();
// 获得对象绑定的地址
T *get() const throw()
cout << "debug15" << endl;
return m_ptr;
// 去掉对象的owner属性
T *release() const throw()
cout << "debug16" << endl;
((auto_ptr<T> *)this)->m_bIsOwner = false;
return m_ptr;
private:
bool m_bIsOwner; // 对象是否拥有为owner的标志
T *m_ptr; // 对象绑定的指针
;
int main()
cout << "------------------------------" << endl;
// 用法错误, 因为构造函数中有explicit, 不允许类型转化
//auto_ptr<int> p = new int(10);
cout << "------------------------------" << endl;
// ok
auto_ptr<int> p(new int(10));
cout << "------------------------------" << endl;
// 下面代码有严重的运行期错误, 实际上是尝试delete栈上的内容
int a = 10;
//auto_ptr<int> p(&a);
cout << "------------------------------" << endl;
auto_ptr<int> p(new int(10));
// 错误, p虽然"看似像"指针, 其本质是对象, delete p;是未定义行为
//delete p;
cout << "------------------------------" << endl;
int *q = new int(10);
auto_ptr<int> p(q);
// 错误, q释放一次, p释放一次, 重复释放啊
//delete q;
cout << "------------------------------" << endl;
auto_ptr<int> p0;
// 有debug3的打印, 但没有debug4, 知道原因了吧
p0 = p0;
cout << "------------------------------" << endl;
auto_ptr<int> p0(new int(10));
// 注意, 这是初始化, 不是复制, 所以不会有debug3的打印
auto_ptr<int> p1 = p0;
cout << "------------------------------" << endl;
auto_ptr<int> p0(new int(10));
auto_ptr<int> p1;
// 注意, 这才是赋值, 所有有debug3, debug4, debug5, debug7, debug9, debug10的打印
// 为什么没有debug6呢? 因为当前对象p1还不是owner
p1 = p0;
cout << "------------------------------" << endl;
auto_ptr<int> p0(new int(10));
auto_ptr<int> p1(new int(20));
// 有debug6的打印, 因为当先释放p1绑定的对象, 否则内存又泄露了啊
p1 = p0;
cout << "------------------------------" << endl;
auto_ptr<int> p0(new int(10));
// 把owner转给p1
auto_ptr<int> p1(p0);
// 终于见到你了, debug8
p0 = p1;
cout << "------------------------------" << endl;
auto_ptr<int> p(new int(10));
// 见到你了, debug13
cout << *p << endl;
cout << "------------------------------" << endl;
auto_ptr<A> p(new A());
// 终于见到你了, debug15
p->fun();
cout << "------------------------------" << endl;
auto_ptr<int> p0(new int(10));
auto_ptr<int> p1(p0);
auto_ptr<int> p2(p1);
// 实际上, p3才是最后的winner, 才是最后的owner, 所以释放堆的重任在p3身上
auto_ptr<int> p3(p2);
cout << "------------------------------" << endl;
// oh, my god, 内存泄露, 本来要delete [] q; 现在析构函数只执行delete q;
int *q = new int[3];
auto_ptr<int> p(q);
cout << "------------------------------" << endl;
// oh, my god, 内存泄露, 本来要delete [] q; 现在析构函数只执行delete q;
int *q = new int[3];
auto_ptr<int> p(q);
// 已经说过, 下面语句会造成内存重复释放
//delete q;
// 最后说明一下, auto_ptr不适合做容器的元素, 这一点我们以后会再次讨论到
return 0;
原文链接:https://blog.csdn.net/stpeace/article/details/45155487
测试用例及其好的一篇博客,思路很清晰
以上是关于智能指针之atuo_ptr源码剖析的主要内容,如果未能解决你的问题,请参考以下文章