智能指针基础std::auto_ptr与new、delete的重载学习笔记

在C/C++中我们malloc/new申请的内存都要自行释放,除非程序结束,否则会造成内存泄漏,这么久以来分配释放已经成为一个习惯,但是有时候还是会有疏漏,忘记释放。而C++中有这么一类东西,它可以替我们释放不再使用且未手动释放的内存,这种所谓的东西就叫做智能指针。而智能指针有多种(std::auto_ptr、boost::scoped_ptr、boost::shared_ptr、boost::scoped_array、boost::shared_array、boost::weak_ptr、boost::intrusive_ptr)今天我们就看看最简单的一种:std::auto_ptr以及最基本的new、delete等运算符的重载基础。

1、C++中new、delete对于内存的管理:

通常new与delete是不可分离的,举例说明:

#include <iostream>

using namespace std;

class A{
public:
    A(){cout<<"A()";}
    ~A(){cout<<"~A()";}
    void func(){
        cout<<"I'am function in class A"<<endl;
    }
private:
    int data;
};
int main()
{   
    A * a = new A[5];
    delete []a;

    A * b = new A;
    delete b;

    return 0;
}

对于该例来说: new与new[]的空间我们均得各自释放,在程序的执行过程中,先构造a[5],即先调用5次构造器,再调用5次析构器。在a[5]回收以后接着调用一次构造器产生b对象,最后delete b;调用析构器并释放b对象空间。

结果如下:

A()A()A()A()A()~A()~A()~A()~A()~A()A()~A()

但是当我们不调用deelte时,则只输出六个A()而不会输出~A()。就是因为程序不能自动调用析构器析构对象释放内存。那么我们采用智能指针的方式作以修改。

2、new、delete重载:

(1)、new、delete的重载
new、new[]、delete、delete[]都可以重载,且有[]与无[]是不一样的,其原型基本是固定的:

void *operator new(size_t);
void operator delete(void *);
void *operator new[](size_t);
void operator delete[](void *);

我们来测试一下重载后的运算符在调用过程中发生了什么:

#include <iostream>
#include <stdlib.h>
#include <string.h>

using namespace std;

class A{
public:
    A(){cout<<"A()"<<endl;}
    ~A(){cout<<"~A()"<<endl;}
    void func(){
        cout<<"I'am function in A"<<endl;
    }
    /*非全局即定制化的,只在new A时调用,即只对A的堆中对象申请有效*/
    void * operator new(size_t size){
        cout<<"size = "<<size<<endl;
        cout<<"operator new()"<<endl;
        void * p = malloc(size);
        memset(p, 0, size);
        //((A*)p)->data = 1;//定制化形式的初始化
        return p;
    }
    void operator delete(void * p){
        cout<<"operator delete()"<<endl;
        free(p);
    }
private:
    int data;
};
/*全局即非定制化的,即使是new int[1]也会调用重载后的*/
void *operator new[](size_t size)
{
    cout<<"size = "<<size<<endl;
    cout<<"operator new[]()"<<endl;
    void * p = malloc(size);
    memset(p, 0, size);
    return p;
}
void operator delete[](void * p)
{
    cout<<"operator delete[]()"<<endl;
    free(p);
}
int main()
{
    A * a = new A[5];//调用的重载new[]会自动调用构造函数
    //delete a;//delete a只会析构一个对象,不会析构整个对象数组
    delete []a;

    A * b = new A;
    delete b;
    return 0;
}

结果如下:
这里写图片描述

3、智能指针智能管理:

了解了new与delete的重载以后,我们再来学习智能指针以及部分原理,将示例修改如下(该例分为三次测试,第一部分即func1()测试普通的new与delete,第二部分即func2()测试系统STL模板提供的智能指针auto_ptr,第三部分即func3()测试我们自己简单实现的智能指针):

#include <iostream>
#include <memory>
using namespace std;

class A{
public:
    A(){cout<<"A()"<<endl;}
    ~A(){cout<<"~A()"<<endl;}
    void func(){
        cout<<"I'am function in A"<<endl;
    }
    int data;
};
class Smart{//智能指针的简单实现,对于智能指针的操作也就是对对象的操作
public:
//接收对象指针并赋给ptr,那么对ptr的操作就是对A对象的操作
    Smart(A*p)
        :ptr(p){}
    ~Smart(){
        delete ptr;
    }
    /*每一种智能指针都需要重载->与*运算符,我们实现的也自然不例外*/
    A *operator->(){//重载->
        return ptr;
    }
    A& operator *(){//重载*
        return *ptr;
    }
private:
    A * ptr;
};
void func1()
{
    A * p = new A;/*申请*/
    delete p;/*对应释放*/
}
void func2()
{   
    auto_ptr<A> ptr(new A);

    (*ptr).func();
    ptr->func();//ptr为对象,其行为表现的像一个指针,是因为重载了->和.
}
void func3()
{
    Smart smt(new A);
    smt->func();//需要重载->
    (*smt).func();//需要重载*
}
int main()
{
    func1();
    cout<<endl;
    func2();
    cout<<endl;
    func3();
    return 0;
}

测试结果:
这里写图片描述
我们可以看到我们简单实现的Smart Point与模板库提供的Smart Point:auto_ptr基本功能已经相差无几,都对->和*进行了重载。

注意: auto_ptr为类模板,auto_ptr<A>为模板类; 也就是说auto_ptr对new的内存进行智能指针的对象传参,操作ptr对象也就相当于操作A的对象,并且delete在ptr离开func函数的栈空间的时候发生。是由封装好的智能指针的类的对象在析构时其析构函数完成的(因为Smart类对象在栈区,Smart类对象为自行析构),而不是凭空会回收的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值