shared_ptr智能指针模板类的简单实现(c++11)

前言

最近突然萌生把stl常用的库都通通自己过一遍的想法,算是对泛型编程的一次学习,也深入理解stl,还是对c++11知识的练习,就从智能指针开始吧。
另外,c++11让c++程序变得简洁优雅了许多,对这门语言有点爱不释手了。

智能指针原理

通过使用引用计数的方式来自动的对动态申请的内存进行释放,保证指针的生存期和安全性。
对智能指针初始化的时候,会将引用计数初始为1,之后每次拷贝或移动赋值时,都对其引用计数加1.
而在其生存期结束,要进行析构时,对其进行引用计数减一,如果引用计数为0,则释放原指针保存的空间。
以前总疑惑 指向同一空间的智能指针也是不同的对象,怎么在一个智能指针析构时对指向同一位置的所有智能指针进行操作呢
其实这个问题很简单, 如果引用计数的变量的空间是动态申请的呢,每个智能指针只保存其指针,那么一个智能指针析构时操作就很容易做到影响所有其他智能指针了。

智能指针需要哪些组成部分

模拟指针行为

智能指针,当然是模拟指针行为的类,所以我们要对解引用运算符和箭头运算符进行重载

T& operator*();//解引用重载
T* operator->();

箭头运算符重载的特殊性

c++primer第五版上关于箭头运算符的原话是

和大多数其他运算符一样(尽管这么做不太好),我们能令operator完成任何我们指定的操作。箭头运算符则不是这样,它永远
不能丢掉成员访问这个最基本的含义
。当我们重载箭头时,可以改变的是从哪个对象当中获取成员,而 * 箭头获取成员
这一事实则永远不变

也就是说,比如我们定义智能指针p;
那么在进行p操作时,等同于对T&操作
而p->abcde操作时,等于(
p)->abcde;

析构函数

拷贝构造函数和拷贝赋值运算符重载

我们的引用计数更改就是在上述函数内完成的,当然需要自定义。
我在此三者基础上,还增加实现了移动赋值的两个函数,搞得有点像标准的三五法则了。
其实不然,因为我们这个程序所有传参中均不涉及深拷贝,所以我们并不需要用移动赋值,此处我只是以学习为目的,想使用右值引用和完美转发而已,读者切勿多想。

代码

//
//  Shared_ptr.hpp
//  demo
//
//  Created by shiyi on 2016/12/10.
//  Copyright © 2016年 shiyi. All rights reserved.
//

#ifndef Shared_ptr_Hpp
#define Shared_ptr_Hpp

#include <stdio.h>
#include <iostream>

using namespace std;

template <typename T>
class Shared_ptr
{
private:
    size_t* m_count;
    T* m_ptr;

public:
    //构造函数
    Shared_ptr() : m_ptr(nullptr), m_count(new size_t)
    {}

    Shared_ptr( T* ptr ) : m_ptr(ptr), m_count(new size_t)
    {
        cout<<"空间申请:"<<ptr<<endl;
        *m_count = 1;
    }

    //析构函数
    ~Shared_ptr()
    {
        --(*m_count);
        if(*m_count == 0)
        {
            cout<<"空间释放:"<<m_ptr<<endl;
            delete m_ptr;
            delete m_count;
            m_ptr = nullptr;
            m_count = nullptr;
        }
    }

    //拷贝构造函数
    Shared_ptr( const Shared_ptr& ptr )
    {
        m_count = ptr.m_count;
        m_ptr = ptr.m_ptr;
        ++(*m_count);
    }

    //拷贝赋值运算符
    void operator=( const Shared_ptr& ptr )
    {
        Shared_ptr(std::move(ptr));
    }

    //移动构造函数
    Shared_ptr( Shared_ptr&& ptr ) : m_ptr(ptr.m_ptr), m_count(ptr.m_count)
    {
        ++(*m_count);
    }

    //移动赋值运算符
    void operator=( Shared_ptr&& ptr )
    {
        Shared_ptr(std::move(ptr));
    }

    //解引用运算符
    T& operator*()
    {
        return *m_ptr;
    }

    //箭头运算符
    T* operator->()
    {
        return m_ptr;
    }

    //重载布尔值操作
    operator bool()
    {
        return m_ptr == nullptr;
    }

    T* get()
    {
        return m_ptr;
    }

    size_t use_count()
    {
        return *m_count;
    }

    bool unique()
    {
        return *m_count == 1;
    }

    void swap( Shared_ptr& ptr )
    {
        std::swap(*this, ptr);
    }

};



#endif /* Shared_ptr_Hpp */

测试代码

#include "Shared_ptr.hpp"

using namespace std;


int main()
{
    Shared_ptr<int> p1(new int);
    *p1 = 222;
    cout<<"值:"<<*p1<<" 引用计数:"<<p1.use_count()<<endl;
    {
        Shared_ptr<int> p2(p1);
        *p2 = 333;
        cout<<"值:"<<*p2<<" 引用计数:"<<p1.use_count()<<endl;

        Shared_ptr<int> p3(p2);
        *p3 = 444;
        cout<<"值:"<<*p3<<" 引用计数:"<<p1.use_count()<<endl;
    }

    cout<<"引用计数:"<<p1.use_count()<<endl;

    Shared_ptr<string> q1(new string("我是string1"));
    cout<<(*(q1)).c_str()<<endl;

    Shared_ptr<string> q2(new string("我是string2"));
    q2.swap(q1);
    cout<<(*(q1)).c_str()<<endl;

    return 0;
}

测试结果

这里写图片描述

请赐予我钱进的动力吧~
0%