unique_ptr的实现原理:简单粗暴的防拷贝
目录
一、使用C++11中的新用法unique_ptr
二、使用c++11模拟实现
三、使用c++98特性实现
四、模拟实现unique_ptr
五、发现问题
一、使用C++11中的新用法unique_ptr
由于限制了拷贝以及赋值
导致缺陷:unique_ptr管理的资源无法共享
void TestUniquePtr()
{
unique_ptr<int> up1(new int(10));
*up1 = 100;
// unique_ptr<int> up2(up1); // 无法进行拷贝构造
unique_ptr<int> up3;
// up3 = up1; // 无法进行赋值运算符重载
}
int main()
{
TestUniquePtr();
_CrtDumpMemoryLeaks();
return 0;
}
二、使用c++11模拟实现
使用了
C++11
中
=delete
这个语法的特性
“尝试引用已经删除的函数”
class CopyBan
{
public:
CopyBan(int c)
: _c(c)
{}
// c++11 实现方式
CopyBan(const CopyBan&) = delete;
CopyBan& operator=(const CopyBan&) = delete;
private:
int _c;
};
三、使用c++98特性实现
将拷贝构造
以及
赋值运算符重载
只声明不定义
并且将其访问权限设置为
private
class CopyBan
{
public:
CopyBan(int c)
: _c(c)
{}
// c++98 实现方式
private:
CopyBan(const CopyBan&);
CopyBan& operator=(const CopyBan&);
int _c;
};
四、模拟实现unique_ptr
无法进行拷贝构造以及对象赋值
#include<iostream>
namespace wei
{
template<class T>
class unique_ptr
{
public:
// RAII
unique_ptr(T* ptr = nullptr)
: _ptr(ptr)
{ }
~unique_ptr()
{
if (_ptr)
{
delete _ptr;
_ptr = nullptr;
}
}
// 具有指针类似的行为
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
T* get()
{
return _ptr;
}
// 禁止拷贝
/*
C++98 只声明不定义拷贝构造函数和赋值运算符重载函数,并将权限修改为private
private:
unique_ptr(const unique_ptr<T>&);
unique_ptr<T> operator=(const unique_ptr<T>&);
*/
C++11
unique_ptr(const unique_ptr<T>&) = delete;
unique_ptr<T> operator=(const unique_ptr<T>&) = delete;
private:
T* _ptr;
};
}
void TestUniquePtr()
{
wei::unique_ptr<int> up1(new int(10));
*up1 = 100;
wei::unique_ptr<int> up2(up1); 拷贝报错
wei::unique_ptr<int> up3(new int(10));
up3 = up1; 赋值报错
}
int main()
{
TestUniquePtr();
_CrtDumpMemoryLeaks();
return 0;
}
五、发现问题
再析构的时候只能进行delete,但如果用malloc申请的空间,就无法进行释放,因为new和delete配套,malloc和free配套,如果有其他类型的空间更无法进行释放,例如FILE类型文件,fopen和fclose配套。
namespace bite
{
template<class T>
class DFDef
{
public:
void operator()(T*& ptr)
{
if (ptr)
{
delete ptr;
ptr = nullptr;
}
}
};
增加一个模版参数,默认使用DFDef的方法进行delete释放资源
template<class T, class DF = DFDef<T>>
class unique_ptr
{
public:
// RAII
unique_ptr(T* ptr = nullptr)
: _ptr(ptr)
{}
~unique_ptr()
{
if (_ptr)
{
//delete _ptr;
// 应该根据用户提供的资源方式去释放
//DF df;
//df.operator()(_ptr); 这几种方式均可以
//df(_ptr);
DF()(_ptr);
}
}
// 具有指针类似的行为
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
T* get()
{
return _ptr;
}
// 防拷贝
// C++11
unique_ptr(const unique_ptr<T>&) = delete;
unique_ptr<T> operator=(const unique_ptr<T>&) = delete;
private:
T* _ptr;
};
}
template<class T>
class Free
{
public:
void operator()(T*& ptr) 其他的几种重载调用
{
if (ptr)
{
free(ptr);
ptr = nullptr;
}
}
};
class FClose
{
public:
void operator()(FILE*& ptr)
{
if (ptr)
{
fclose(ptr);
ptr = nullptr;
}
}
};
template<class T>
class deleteArray
{
public:
void operator()(T*& ptr)
{
if (ptr)
{
delete[] ptr;
ptr = nullptr;
}
}
};
#include <malloc.h>
void TestUniquePtr()
{
bite::unique_ptr<int> up1(new int(10));
*up1 = 100;
bite::unique_ptr<int, Free<int>> up2((int*)malloc(sizeof(int)));
bite::unique_ptr<FILE, FClose> up3(fopen("111.txt", "w"));
// bite::unique_ptr<int> up4(new int[10]);
// 注意:一般不会将连续的空间使用unique_ptr管理
// 因为:STL中已经存在了vector
}
// 缺陷:unique_ptr管理的资源无法共享
int main()
{
TestUniquePtr();
_CrtDumpMemoryLeaks();
return 0;
}