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;
}

测试结果

这里写图片描述

shared_ptr是C++中用于动态内存管理的智能指针之一。它能够记录对象被引用的次数,主要用于管理动态创建的对象的销毁。使用shared_ptr可以避免内存泄漏和悬挂指针等问题。 在C++中,实现shared_ptr通常需要以下几个步骤: 1. 定义一个模板类,例如SHARED_ptr,该类将作为智能指针使用。 2. 在SHARED_ptr类中,定义一个指针成员变量ptr,用于指向实际的对象。 3. 在SHARED_ptr类中,定义一个计数器类的指针成员变量refcount,用于记录对象被引用的次数。 4. 在SHARED_ptr类中,实现构造函数,用于初始化指针和计数器。 5. 在SHARED_ptr类中,实现拷贝构造函数和赋值操作符重载,用于处理多个智能指针共享同一对象的情况。 6. 在SHARED_ptr类中,实现析构函数,用于释放对象的内存空间。 7. 在SHARED_ptr类中,实现箭头运算符重载和解引用运算符重载,用于访问对象的成员函数和数据。 8. 在SHARED_ptr类外部,实现计数器类RefCount,用于记录对象被引用的次数,并在引用次数为0时释放对象的内存空间。 实现shared_ptr的详细代码如下所示: ```cpp template <class T> class SHARED_ptr { private: T* ptr; // 用来指向堆区对象 RefCount<T>* refcount; // 指向计数器对象的指针 public: SHARED_ptr(T* p) : ptr(p), refcount(new RefCount<T>()) { refcount->increment(); } SHARED_ptr(const SHARED_ptr<T>& other) : ptr(other.ptr), refcount(other.refcount) { refcount->increment(); } ~SHARED_ptr() { if (refcount->decrement() == 0) { delete ptr; delete refcount; } } T* operator->() const { return ptr; } T& operator*() const { return *ptr; } SHARED_ptr& operator=(const SHARED_ptr<T>& other) { if (this != &other) { if (refcount->decrement() == 0) { delete ptr; delete refcount; } ptr = other.ptr; refcount = other.refcount; refcount->increment(); } return *this; } }; ``` 以上是一个简单的C++实现shared_ptr的示例代码。通过使用shared_ptr,我们可以方便地管理动态创建的对象的生命周期,并避免内存泄漏和悬挂指针等问题。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值