现代C++02:手动实现智能指针

本文探讨了如何使用C++模板创建一个智能指针类,以实现对象的自动管理。内容包括模板化的smart_ptr类,实现拷贝构造、赋值操作、类型转换以及引用计数。此外,还讨论了移动构造函数、类型安全转换以及在智能指针中应用C++11的unique_ptr行为。文章最后展示了如何通过引用计数实现多个智能指针共享对象的场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

自己动手实现智能指针

上一讲实现的类

class shape_wrapper{
   
public:
    explicit shape_wrapper(shape* ptr=nullptr):ptr_(ptr){
   }
    ~shape_wrapper(){
   delete ptr_;}
    shape* get() const {
   return ptr_;}
private:
    shape* ptr_;
};

该对象析构的时候,会对超出作用域的对象进行释放。

但是存在缺点:

  1. 这个类只适用于shape类
  2. 这个类的行为不够像指针
  3. 拷贝该类对象会引发程序行为异常

模板化和易用性

如果想让这个类能包含任意类型的指针,我们需要将它变为一个类模板,代码如下

template<typename T>
class smart_ptr{
   
public:
    explicit smart_ptr(T* ptr=nullptr):ptr_(ptr){
   }
    ~smart_ptr(){
   delete ptr_};
    T* get() const{
   return ptr_;}
private:
    T* ptr_;
};

在开头添加模板声明template<typename T>,然后将代码中的shape替换为T就能完成定义。

模板的使用也很简单,把原来的shape_wrapper改为smart_ptr<shape>就行。

目前这个类还是与指针类有差异的:

  • 不能用*运算符解引用
  • 不能用->运算符指向对象成员
  • 不能像指针一样用在布尔表达式里

所以增加几个成员函数就能解决:

template<typename T>
class smart_ptr{
   
public:
	...
	T& operator()const{
   return *ptr_;}
	T* operator()const{
   return ptr_;}
	operator bool()const{
   return ptr_;}
};

拷贝构造和赋值

最简单的情况是禁止拷贝。

template<typename T>
class smart_ptr{
   
	...
	smart_ptr(const smart_ptr&)=delete;
	smart_ptr& operator=(const smart_ptr&)=delete;
	...
};

禁用这两个函数会解决一种可能出错的情况,当smart_ptr<shape>ptr2{ptr1};在编译时不会出错,在运行时会有未定义行为–通常会对同一内存释放两次,通常情况下会导致程序崩溃。

是否可以考虑在拷贝智能指针时,将对象拷贝一份?不行,因为使用智能指针的目的就是为了减少对象的拷贝。而且我们的指针类型是shape,但实际指向的应该是circle或者triangle之类的对象。一般而言,没有通用的方法可以通过基类的指针构造出一个子类的对象。

尝试在拷贝时转移指针的所有权:

template<typename T>
class smart_ptr{
   
    //拷贝构造函数,等号右边或括号中的值是other
    //完成操作后,初始值被释放,新构造出的值指向初始值之前的地址
    smart_ptr(smart_ptr& other){
   
        ptr_=other.release();
    }
    //拷贝赋值函数,rhs是等号右边的值
    //通过拷贝构造一个临时对象,交换临时对象和当前对象的指针
    //结果就是等号两边的对象都完成了
    smart_ptr& operator=(smart_ptr& rhs){
   
        smart_ptr(rhs).swap(*this);
    }
    T* release(){
   
        T* ptr =ptr_;
        ptr_=nullptr;
        return ptr;
    }
    void swap(smart_ptr& rhs){
   
        using std::swap;
        swap(ptr_,rhs.ptr_);
    }
}

赋值分为拷贝构造和交换两步,异常只可能在第一步发生;而第一步如果发生异常的话,this对象完全不受任何影响。无论拷贝构造成功与否,结果只是赋值成功和赋值没有效果两种状态,而不会发生因为赋值破坏当前对象这种情况。

这个是auto_ptr的定义,但是已经被废除了,上面存在的最大问题在于会让程序员非常容易犯错,一不小心把他传递给另一个smart_ptr,你就不再拥有这个对象。

“移动”指针?

使用移动来改善行为,代码如下:

template <typename T>
class smart_ptr{
   
    ...
    smart_ptr(smart_ptr&& other){
   
        ptr_=other.release();
    }
    smart_ptr& operator=(smart_ptr rhs){
   
        rhs.swap(*this);
        return *
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值