#pragma once
// 智能指针
// 定义个类来封装资源的分配和释放,在构造 函数完成资源的分配和初始化,在析构函数完成资源的
// 清理,可以 保证资源的正确初始化和释放。
// 这里简单实现 AutoPtr、 ScopedPtr、ScopedArray以及 SharedPtr
//------------------------------SmartPtr.h-------------------
template<typename T>
class AutoPtr //缺点 定义多个指向同一空间的ptr 只有一个控制 其他的都失效了
{
public:
AutoPtr(T* ptr = NULL)
:_ptr(ptr)
{}
AutoPtr(AutoPtr<T>& ap)// 这里没有用const 为了修改ap的成员
:_ptr(ap._ptr)
{
ap._ptr = NULL;// 只能有一个智能指针 指向空间 (控制权)
}
AutoPtr<T>& operator= (AutoPtr<T>& ap)
{
if(_ptr != ap._ptr)//排除 1 自赋值 2(常常会忽略) 虽然不是自赋值 但两个的_ptr 指向同一空间
{
//第3种情况 两个不指向同一空间
delete _ptr;
_ptr = ap._ptr;
ap._ptr = NULL;
return *this;
}
}
~AutoPtr()
{
if(_ptr)
{
cout<<"delete _ptr"<<_ptr<<endl;
delete _ptr;
}
}
T& operator*()
{
return *_ptr;
}
// 从原理来说 要两个->
// operator->()返回的是T* 再->才能访问对应成员
// 这里编译器做了处理
// 如 operator++() operator++(int)
T* operator->()
{
return _ptr;
}
protected:
T* _ptr;
};
void testAutoPtr()
{
struct A
{
int _a;
};
AutoPtr<int> ap1(new int(1));
AutoPtr<int> ap2(ap1);
AutoPtr<int> ap3(new int(2));
ap3 = ap2;
*ap3 = 10;//运算符重载T& operator*()
A* p4 = new A;
p4->_a = 10;
AutoPtr<A> ap4(new A);//运算符重载 T* operator->()
ap4->_a = 4;
}
// AutoPtr 的老版本的写法 比之前的多了一个bool 类型的_owner
// 缺点 : 在
// AutoPtr<int> ap1(new int (1));
//if (1)
// {
// AutoPtr<int> ap2(ap1);
// }
// 这种场景下 ap2出了作用域 析构 释放空间 但ap1指针还指向那块空间 很危险(野指针)
template<typename T>
class AutoPtr
{
public:
AutoPtr(T* ptr = NULL)
:_ptr(ptr)
{}
AutoPtr(AutoPtr<T>& ap)
{
_ptr = ap._ptr;
_owner = true;
ap._owner = false;
}
~AutoPtr()
{
if (_owner)
{
delete _ptr;
_owner = false;
}
}
AutoPtr<T>& operator=(AutoPtr<T>& ap)
{
if(_ptr != ap._ptr)//排除 1 自赋值 2(常常会忽略) 虽然不是自赋值 但两个的_ptr 指向同一空间
{
//第3种情况 两个不指向同一空间
if (_owner == true)
{
delete _ptr;
}
_ptr = ap._ptr;
ap._owner = false;
_owner = true;
return *this;
}
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
protected:
T* _ptr;
bool _owner;
};
void testAutoPtr()
{
struct A
{
int _a;
};
AutoPtr<int> ap1(new int(1));
AutoPtr<int> ap2(ap1);
AutoPtr<int> ap3(new int(2));
ap3 = ap2;
*ap3 = 10;//运算符重载T& operator*()
A* p4 = new A;
p4->_a = 10;
AutoPtr<A> ap4(new A);//运算符重载 T* operator->()
ap4->_a = 4;
}
//-----------------------------------------------------
template<typename T>
class ScopedPtr //缺点 不能解决 两个对象之间的拷贝
{
public:
ScopedPtr(T* ptr = NULL)
:_ptr(ptr)
{}
~ScopedPtr()
{
if (_ptr)
{
cout<<"delete:"<<_ptr<<endl;
delete _ptr;
}
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
//与AutoPtr相比 简单 粗暴 直接加protected:防止拷贝构造和赋值重载 同时也防止别人在类外实现
protected:
ScopedPtr(ScopedPtr<T>& sp);
ScopedPtr<T>& operator=(ScopedPtr<T>& sp);
protected:
T* _ptr;
};
void TestScopedPtr()
{
ScopedPtr<int> sp1(new int(1));
// ScopedPtr<int> sp2(sp1);
}
//------------------------------------------
template<typename T>
class SharedPtr
{
public:
SharedPtr(T* ptr = NULL)
:_ptr(ptr)
,_pCount(new long(1))
{}
~SharedPtr()
{
_Release();
}
SharedPtr(const SharedPtr<T>& sp)
:_ptr(sp._ptr)
,_pCount(sp._pCount)
{
++(*_pCount);
}
/************************************
SharedPtr<T>& operator=(const SharedPtr<T>& sp)
{
// 考虑多种情况
// 1 sp1 = sp1
// 2 sp1 = sp2; ==>sp1,sp2管理着同一块内存
// 3 sp1 = sp3 sp1与sp3 指向的空间不同
if (_ptr != sp._ptr)//排除1、 2
{
_Release();
_ptr = sp._ptr;
_pCount = sp._pCount;
(*_pCount)++;
}
return *this;
}
***************************************/
SharedPtr<T>& operator=(SharedPtr<T> sp)//不用引用 不用const
{
//现代 写法
swap(_ptr, sp._ptr);
swap(_pCount, sp._pCount);
return *this;
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
long UseCount()
{
return *_pCount;
}
T* GetPtr()
{
return _ptr;
}
protected:
void _Release()
{
if(--(*_pCount) == 0)
{
delete _ptr;
delete _pCount;
}
}
protected:
T* _ptr;
long* _pCount;
};
void TestSharedPtr()
{
SharedPtr<int> sp1(new int(1));
SharedPtr<int> sp2(sp1);
SharedPtr<int> sp3(sp1);
// int a;
// const int* p = &a;
//// int const * p = &a;
// // error: (*p) = 1; 要是可修改的左值
// // p = &a;
//// int * p2 = p; // error 不能从const到非const
// int * const p3 = &a;
////error p3 = &a;要是可修改的左值
// *p3 = 5;
cout<<"sp1:"<<sp1.UseCount()<<endl;
cout<<"sp2:"<<sp2.UseCount()<<endl;
cout<<"sp3:"<<sp3.UseCount()<<endl<<endl;
sp1 = sp1;
sp1 = sp2;
cout<<"sp1:"<<sp1.UseCount()<<endl;
cout<<"sp2:"<<sp2.UseCount()<<endl;
cout<<"sp3:"<<sp3.UseCount()<<endl<<endl;
SharedPtr<int> sp4(new int(2));
sp1 = sp4;
cout<<"sp1:"<<sp1.UseCount()<<endl;
cout<<"sp2:"<<sp2.UseCount()<<endl;
cout<<"sp3:"<<sp3.UseCount()<<endl;
cout<<"sp4:"<<sp4.UseCount()<<endl;
}
//-----------------------------------------------------
template<typename T>
class ScopedArray
{
public:
ScopedArray(T* ptr = NULL)
:_ptr(ptr)
{}
~ScopedArray()
{
if (_ptr)
{
delete[] _ptr;
}
}
/*T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}*/
//不需要重载上面两个 用operator[]
T& operator[](size_t index)
{
return _ptr[index];
}
protected:
ScopedArray(const ScopedArray<T>& sp);
ScopedArray<T>& operator=(const ScopedArray<T>& sp);
protected:
T* _ptr;
};
void TestScopedArray()
{
struct V
{
int _v;
};
ScopedArray<V> sa(new V[10]);
sa[0]._v = 1;
sa[2]._v = 11;
}
//-----------------------------test.cpp--
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
#include "SmartPtr.h"
//void Test1()
//{
// int* p = new int(1);
//
// if (1)
// {
// delete p;
//
// return;
// }
// delete p;
//}
//void DoSomething()
//{
// if (1)
// {
// throw 1;
// }
//}
//
//void Test2()
//{
// int* p = new int(1);
// try
// {
// DoSomething();
// }
// catch(...)
// {
// delete p;
// throw;
// }
//
// delete p;
//}
//
//void Test1()
//{
// int* p = new int(1);
// AutoPtr<int> ap(p);
// if (1)
// {
// // delete p;
//
// return;
// }
// // delete p;
//}
//void DoSomething()
//{
// if (1)
// {
// throw 1;
// }
//}
//
//void Test2()
//{
// int* p = new int(1);
// AutoPtr<int> ap(p);
//
// DoSomething();
// /*try
// {
// DoSomething();
// }
// catch(...)
// {
// delete p;
// throw;
// }
//
// delete p;*/
//}
//
//int main()
//{
// try
// {
// Test1();
// Test2();
// }
// catch(...)
// {
// cout<<"未知异常"<<endl;
// }
//
// getchar();
// return 0;
//}
int main()
{
//TestSharedPtr();
TestScopedArray();
getchar();
return 0;
}
//==================================
//==================================
//==================================
// 续
//1、 增加AutoPtr的另一种写法(老版本写法)
//2、 模拟SharedPtr的定置删除器
//3、 定置删除器和循环引用的场景并理解
// 智能指针 使用库中的
#include <memory> // 这个头文件包含 auto_ptr 、unique_ptr 、shared_ptr
using namespace std;
void test_auto_ptr()
{
//auto_ptr 用到 memory头文件
auto_ptr<int> ap1(new int(1));
auto_ptr<int> ap2(ap1);
}
// scoped_ptr 在 C++ 11 中叫 unique_ptr
void test_scoped_ptr()
{
unique_ptr<int> sp1(new int(1));
// error unique_ptr<int> sp2(sp1);
}
void test_shared_ptr1()
{
shared_ptr<int> sp1(new int (1));
cout<<"sp1:"<<sp1.use_count()<<endl;
shared_ptr<int> sp2(sp1);
cout<<"sp1:"<<sp1.use_count()<<endl;
cout<<"sp2:"<<sp2.use_count()<<endl;
}
//--------------------------------------------------
void test_shared_ptr2()
{
struct Node
{
//Node* _next;
//Node* _prev;
shared_ptr<Node> _next; // 容易引起循环引用 解决方法详见 下面weak_ptr
shared_ptr<Node> _prev;
~Node()
{
cout<<"delete:"<<this<<endl;
}
};
// 循环引用问题 这几步都用的是 智能指针 cur next _next _prev
shared_ptr<Node> cur(new Node());
shared_ptr<Node> next(new Node());
// 没有下面两句就可以释放的 下面两句引起循环引用
// *********重点***********
//cur->_next = next;
//next->_prev = cur;
// 分析 循环引用 原因 图
}
// 解决循环引用问题 weak_ptr
void test_shared_ptr3()
{
struct Node
{
//Node* _next;
//Node* _prev;
/*shared_ptr<Node> _next;
shared_ptr<Node> _prev;*/
// 解决循环引用 (运用弱指针weak_ptr 不增加shared_ptr的count 增加自己weak_ptr 的引用计数 count)
//weak_ptr 重载了operator->() operator*()
// weak_ptr 唯一的目的 就是解决shared_ptr的死穴 循环引用问题
// wead_ptr不能单独使用 例如没有weak_ptr<int> (int*)类型的构造函数 只有weak_ptr<shared_ptr> (shared_ptr&)
// 用弱指针 场景 内部含有指向对方的 智能指针
weak_ptr<Node> _next;
weak_ptr<Node> _prev;
~Node()
{
cout<<"delete:"<<this<<endl;
}
};
// 循环引用问题 这几步都用的是 智能指针 cur next _next _prev
shared_ptr<Node> cur(new Node());
shared_ptr<Node> next(new Node());
cout<<"cur"<<cur.use_count()<<endl;
cout<<"next:"<<next.use_count()<<endl;
// *********重点**** weak_ptr解决循环引用问题 *******
cur->_next = next;
next->_prev = cur;
cout<<"cur"<<cur.use_count()<<endl;
cout<<"next:"<<next.use_count()<<endl;
}
//--------------------------------------------------------------------
// 仿函数
// 原理: 重载operator() ()
// 使用: 用Less创建一个结构体对象less
// 使用less() 看起来像函数调用 其实是使用了对象的operator()操作 这样传参传如一个less对象就能用它的对应的operator()方法 这样就能定制删除器了
template<typename T>
struct Less
{
bool operator() (const T& L, const T& R)
{
return L < R;
}
};
void test_less()
{
Less<int> less;
cout<<less(1, 2)<<endl;
}
//------------------------------
//模拟SharedPtr的定置删除器
void test_shared_ptr4()
{
//场景1 没问题
int* p1 = (int*)malloc(sizeof(int) * 10);
shared_ptr<int> sp1(p1);
// 场景2 析构出错 不能将FILE* 转换为int*
//FILE* p2 = fopen("test.txt", "r");
//shared_ptr<int> sp2(p2);
}
// 定制删除器
struct Free
{
void operator()(void* ptr)
{
cout<<"Free:"<<ptr<<endl;
free(ptr);
}
};
struct FileClose //场景2的 删除器
{
void operator()(void* fp)
{
cout<<"FileClose:"<<fp<<endl;
if (fp != NULL)
{
fclose((FILE*)fp);
}
}
};
void test_Free()
{
//场景1 没问题
int* p1 = (int*)malloc(sizeof(int) * 10);
// *********** 重点 定制删除器的应用
// Free() 创建一个匿名对象
shared_ptr<int> sp1(p1, Free()); // 重点 【给库中的 shared_ptr 传入 Free()的匿名对象】 下边改进的自己的SharedPtr也用到这方法
// 场景2 析构出错 不能将FILE* 转换为int*
// 定制删除器后不出错
FILE* p2 = fopen("test.txt", "r");
shared_ptr<FILE> sp2(p2, FileClose());
}
//---------------------------------
//用定制删除器 改进 之前的SharedPtr
template<typename T, typename D = DefaultDel<T>>//D 是删除器结构体类型
class SharedPtr
{
public:
SharedPtr(T* ptr = NULL)
:_ptr(ptr)
,_pCount(new long(1))
{}
SharedPtr(T* ptr, D del)
:_ptr(ptr)
,_pCount(new long(1))
,_del(del)
{}
~SharedPtr()
{
_Release();
}
SharedPtr(const SharedPtr<T, D>& sp)
:_ptr(sp._ptr)
,_pCount(sp._pCount)
{
++(*_pCount);
}
SharedPtr<T, D>& operator=(SharedPtr<T,D> sp)//不用引用 不用const
{
//现代 写法
swap(_ptr, sp._ptr);
swap(_pCount, sp._pCount);
return *this;
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
long UseCount()
{
return *_pCount;
}
T* GetPtr()
{
return _ptr;
}
protected:
void _Release()
{
if(--(*_pCount) == 0)
{
//delete _ptr;
//********更换成――del()************
_del(_ptr);
delete _pCount;
}
}
protected:
T* _ptr;
long* _pCount;
D _del;
};
// 删除器
template<typename T>
struct DefaultDel
{
void operator()(T* ptr)
{
delete ptr;
}
};
template<typename T>
struct FreeShared
{
void operator()(T* ptr)
{
free(ptr);
}
};
void TestDeleter()
{
SharedPtr<int, DefaultDel<int>> sp1(new int(10));
SharedPtr<int, FreeShared<int>> sp2((int*)malloc(sizeof(int) * 2));
SharedPtr<int> sp3(new int(1));
}
//-----------------------------------------------------
#include "SmartPtr.h"
int main()
{
//test_auto_ptr();
//test_shared_ptr4();
//test_less();
test_Free();
//TestDeleter();
getchar();
return 0;
}