C++自制简易版智能指针实现过程分析

目录

1. 引言

2.  智能指针的定义以及粗略实现

2.1 智能指针的定义

2.2 智能指针SmartPtr的粗略实现

3. SmartPtr的优化

3.1 分析SmartPtr的构造函数、析构函数以及赋值

3.2 测试指针是否为空

3.3 使SmartPtr转换为T*指针

4. 实现SmartPtr之间的转换

5.  优化后智能指针实现


1. 引言

C++中,由于没有垃圾回收机制,当程序员申请了某些资源(譬如new 某个对象A),如果程序员自己负责释放这些资源,则很可能会产生内存泄露,因此现代C++11引进了智能指针来尽量降低资源泄露的可能。本博客便是我自己在学习more effective C++ 的过程,记录自制简易版智能指针的过程。方便以后复习。

2.  智能指针的定义以及粗略实现

2.1 智能指针的定义

智能指针是看起来、用起来像C++内建指针的对象

2.2 智能指针SmartPtr的粗略实现

智能指针可以像内建指针一样,指向各个类型,因此需要考虑使用C++11 模板实现,其第一版粗略实现如下:

#ifndef CPLUS_SMARTPTR_H
#define CPLUS_SMARTPTR_H

template <typename T>
class SmartPtr {
public:
    SmartPtr(const SmartPtr& rhs);
    SmartPtr(T* pointer = 0);
    ~SmartPtr() {
        delete _ptr;
    };

    SmartPtr& operator=(const SmartPtr& rhs);

    T* operator->() const;
    T& operator*() const;

private:
    T* _ptr;
};

template <typename T>
SmartPtr<T>::SmartPtr(T *pointer) : _ptr(pointer) {

}

template <typename T>
SmartPtr<T>::SmartPtr(const SmartPtr &rhs) : _ptr(rhs._ptr) {

}

template <typename T>
SmartPtr<T>& SmartPtr<T>::operator=(const SmartPtr &rhs) {
    if (this == &rhs) return *this;
    _ptr = rhs._ptr;
    return *this;
}

template <typename T>
T * SmartPtr<T>::operator->() const {
    return _ptr;
}

template <typename T>
T & SmartPtr<T>::operator*() const {
    return *_ptr;
}
#endif //CPLUS_SMARTPTR_H

利用上述SmartPtr,测试程序如下

#include <iostream>
#include "smartptr.h"

class TestClass {
public:
    void func() {
        std::cout << "TesstClass" << std::endl;
    }
};

int main() {
    SmartPtr<TestClass> smartPtr(new TestClass);
    smartPtr->func();
    
    return EXIT_SUCCESS;
}

3. SmartPtr的优化

3.1 分析SmartPtr的构造函数、析构函数以及赋值

如下述代码,当调用SmartPtr拷贝构造函数, 会导致_ptr被删除两次,也即double free 问题。因此上述拷贝构造函数实现有问题,需要优化。

    SmartPtr<TestClass> smartPtr(new TestClass);
    auto sp = smartPtr;
    sp->func();

有三种优化方案:禁止拷贝 或者 引用计数 或者 转移所有权(本文选择转移所有权

拷贝构造函数优化后如下:

SmartPtr(SmartPtr& rhs);
template <typename T>
SmartPtr<T>::SmartPtr(SmartPtr &rhs) : _ptr(rhs._ptr) {
    rhs._ptr = 0;
}

赋值拷贝函数优化如下:

SmartPtr& operator=(SmartPtr& rhs);
template <typename T>
SmartPtr<T>& SmartPtr<T>::operator=(SmartPtr &rhs) {
    if (this == &rhs) return *this;
    delete _ptr;
    _ptr = rhs._ptr;
    rhs._ptr = 0;
    return *this;
}

3.2 测试指针是否为空

如下代码,测试smartPtr为空失败,这是因为SmartPtr是一个模板,其smartPtr是一个对象,该对象并没有相应的方法与0比较。

那么如何使SmartPtr可以看起来像内建指针一样判断为空呢?

其解决方案为,提供一个隐式类型转换操作符,增加的隐式转换操作符如下

 operator void*() {
        return _ptr;
    }

3.3 使SmartPtr转换为T*指针

有时候为了兼容旧的接口,需要传递原生指针至兼容接口,那么此时便需要将SmartPtr转换成T*,那么如何获得SmartPtr中的T*呢?

有两种方案:提供隐式类型转换操作符 或者 提供一个get方法获得T*

提供隐式转换操作符的实现如下:

operator T*() {
        return _ptr;
    }

提供get 方法获得T*实现如下:

T* get() {
        return _ptr;
    }

4. 实现SmartPtr之间的转换

测试代码如下:

函数func_test(SmartPtr<TestClass>& test) 的形参为 SmartPtr<TestClass> 而当传入smartPtrA 或者 smartPtrB时,编译会报错。

原因是smartPtrA 或者 smartPtrB或者smartPtr是不同的对象,不存在相应的对象转换,因此若要使继承关系的smartPtrA 或者 smartPtrB或者smartPtr能相互转换,则需要自定义转换函数。

#include <iostream>
#include "smartptr.h"

class TestClass {
public:
    virtual void func() {
        std::cout << typeid(*this).name() << std::endl;
    }
    virtual ~TestClass() {}
};

class TestA : public TestClass {
public:
    virtual void func() {
        std::cout << typeid(*this).name() << std::endl;
    }
};

class TestB : public TestClass {
    virtual void func() {
        std::cout << typeid(*this).name() << std::endl;
    }
};

void func_test(SmartPtr<TestClass>& test) {
    test->func();
}

int main() {
    SmartPtr<TestClass> smartPtr(new TestClass);
    SmartPtr<TestA> smartPtrA(new TestA);
    SmartPtr<TestB> smartPtrB(new TestB);
    func_test(smartPtr);
    func_test(smartPtrA);
    func_test(smartPtrB);

    return EXIT_SUCCESS;
}

对于C++11来说,可以定义模板转换操作符,其实现如下:

template <typename newType>
    operator SmartPtr<newType>() {
        return SmartPtr<newType>(_ptr);
    }

5.  优化后智能指针实现

 

#ifndef CPLUS_SMARTPTR_H
#define CPLUS_SMARTPTR_H

template <typename T>
class SmartPtr {
public:
    SmartPtr(const SmartPtr& rhs);
    SmartPtr(SmartPtr& rhs);
    SmartPtr(T* pointer = 0);
    ~SmartPtr() {
        delete _ptr;
    };

    SmartPtr& operator=(const SmartPtr& rhs);
    SmartPtr&operator=(SmartPtr& rhs);

    template <typename newType>
    operator SmartPtr<newType>() {
        return SmartPtr<newType>(_ptr);
    }

    operator bool() {
        return _ptr != nullptr;
    }
/*
    operator T*() {
        return _ptr;
    }*/

    T* get() {
        return _ptr;
    }

    T* operator->() const;
    T& operator*() const;

private:
    T* _ptr;
};

template <typename T>
SmartPtr<T>::SmartPtr(T *pointer) : _ptr(pointer) {

}

template <typename T>
SmartPtr<T> & SmartPtr<T>::operator=(SmartPtr<T> &rhs) {
    if (this == &rhs) return *this;
    delete _ptr;
    _ptr = rhs._ptr;
    rhs._ptr = 0;
    return *this;
}

template <typename T>
SmartPtr<T>::SmartPtr(SmartPtr& rhs) : _ptr(rhs._ptr) {
    rhs._ptr = 0;
}

template <typename T>
SmartPtr<T>::SmartPtr(const SmartPtr &rhs) : _ptr(rhs._ptr) {
}

template <typename T>
SmartPtr<T>& SmartPtr<T>::operator=(const SmartPtr &rhs) {
    if (this == &rhs) return *this;
    delete _ptr;
    _ptr = rhs._ptr;
    return *this;
}

template <typename T>
T * SmartPtr<T>::operator->() const {
    return _ptr;
}

template <typename T>
T & SmartPtr<T>::operator*() const {
    return *_ptr;
}
#endif //CPLUS_SMARTPTR_H

注意:该智能指针,在不同指针类型之间转换会导致double free,正在研究解决方案

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qls315

感觉好可打赏几毛钱增强更新动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值