C++ 之实现自己的 shared_ptr
/*shared_ptr.h 文件*/
/*********************************************************
> File Name: shared_ptr.h
> Author: Liu Shengxi
> Mail: 13689209566@163.com
> Created Time: 2018年06月05日 星期二 15时35分48秒
*****************************************************/
#ifndef _SHARED_PTR_H
#define _SHARED_PTR_H
template<typename> class shared_ptr ;
template< class T >
void swap( shared_ptr<T>& lhs, shared_ptr<T>& rhs ) noexcept
{
std::cout << "swap out object " << std::endl ;
lhs.swap(rhs);
}
template<typename T>
class shared_ptr {
using DelFuncPtr = void (*)(T*) ;
public:
shared_ptr():m_ptr(nullptr),
count_ptr( new size_t(0)),del(nullptr)
{
}
explicit shared_ptr(T *ptr ,DelFuncPtr temp = nullptr ):
m_ptr(ptr),count_ptr(new size_t(1)), del(temp )
{
}
//拷贝构造函数
shared_ptr(const shared_ptr &hp):
m_ptr(hp.m_ptr),count_ptr(hp.count_ptr),del(hp.del)
{
++(*count_ptr) ; //引用计数加1
}
//拷贝赋值运算符
shared_ptr& operator=( shared_ptr &rhs){
swap(*this,rhs);
return *this;
}
//析构函数
~shared_ptr(){
--(*count_ptr);
if((*count_ptr) == 0 ){
del ? del(m_ptr):
delete m_ptr;
delete count_ptr ;
}
m_ptr = nullptr ;
count_ptr =nullptr ;
}
size_t use_count(){ return (*count_ptr);}
T& operator*() { return *m_ptr ;}
T* operator->() { return m_ptr ; }
void swap(shared_ptr &hp){
std::cout << "swap in object " << std::endl ;
using std::swap ;
swap(m_ptr,hp.m_ptr);
swap(count_ptr,hp.count_ptr);
swap(del,hp.del);
}
void reset( ){
if((*count_ptr) == 1) {
delete m_ptr;
delete count_ptr ;
m_ptr = nullptr ;
count_ptr =nullptr ;
}
}
void reset( T *hp ,DelFuncPtr del = nullptr ){
shared_ptr temp(hp,del);
swap(temp);
}
private:
T* m_ptr = nullptr ;
size_t* count_ptr = nullptr ;
//思考一下为什么是size_t*,而不是 size_t ? ?
DelFuncPtr del = nullptr ; //自定义的删除器
};
#endif
/*main.cpp 文件*/
/*************************************************************************
> File Name: main.cpp
> Author: Liu Shengxi
> Mail: 13689209566@163.com
> Created Time: 2018年06月05日 星期二 15时39分58秒
************************************************************************/
#include <iostream>
#include"shared_ptr.h"
using namespace std ;
struct Foo {
Foo() { std::cout << "Foo()\n"; }
~Foo() { std::cout << "~Foo()\n"; }
Foo(const Foo&) { std::cout << "Foo copy ctor\n"; }
Foo(Foo&&) { std::cout << "Foo move ctor\n"; }
};
struct Fooo {
Fooo(int n = 0) noexcept : bar(n) { std::cout << "Fooo: constructor, bar = " << bar << '\n'; }
~Fooo() { std::cout << "Fooo: destructor, bar = " << bar << '\n'; }
int GetBar() const noexcept { return bar; }
private:
int bar;
};
struct D {
void bar() { std::cout << "Call deleter D::bar()...\n"; }
void operator()(Foo* p) const
{
std::cout << "Call delete from function object...\n";
delete p;
}
};
int main()
{
std::cout << "shared_ptr constructor with no managed object\n";
{
shared_ptr<Foo> sh1;
}
std::cout << "shared_ptr constructor with object and test swap \n";
{
shared_ptr<Foo> sh2(new Foo);
std::cout << sh2.use_count() << '\n';//1
shared_ptr<Foo> sh3(sh2);
std::cout << sh3.use_count() << '\n';// 2
shared_ptr<int> sh4(new int(4444)) ;
shared_ptr<int> sh5(new int(5555)) ; // test swap()
sh4.swap(sh5);
cout << "sh4 == " << *sh4 << "\nsh5 == " << *sh5 << endl ; // 5555 4444
swap(sh4,sh5);
cout << "sh4 == " << *sh4 << "\nsh5 == " << *sh5 << endl ; //4444 5555
}
std::cout << "shared_ptr constructor with deleter\n";
{
shared_ptr<Foo> sh5(new Foo, [](Foo* p) {
std::cout << "Call delete from lambda...\n";
delete p;
});
}
{
shared_ptr<Fooo> sptr(new Fooo(111)) ;
std::cout << "The first Fooo's bar is " << sptr->GetBar() << "\n"; // 111
sptr.reset(new Fooo); //先搞一个新的出来,然后干掉原来的,避免自赋值
std::cout << "The second Fooo's bar is " << sptr->GetBar() << "\n"; // 0
}
}
运行结果:
总结:
- 什么是size_t 类型
它是一个与机器相关的unsigned类型,其大小足以保证存储内存中对象的大小。一般用作下标类型 。 - 为什么是size_t*,而不是 size_t ? ?
因为你要定义的是行为像指针的类而不是像值的类,在多个指针共同指向同一个对象时,只需要拷贝指针,利用指针让它引用计数加一就可以了。如果一个指针被析构时,也是通过指针让引用计数减一即可。
如果为size_t类型的成员变量,在多个shared_ptr对象指向同一资源时,其中一个shared_ptr对象析构了count_ptr = count_ptr -1,但是不会影响到其他shared_ptr对象。所以使用size_t* 来达到多个shared_ptr对象指向同一资源的能够共享count_ptr 的目的。
3 . 另外注意删除器的书写方式和成员函数swap与友元函数swap的书写即可