动态内存与智能指针

来源:互联网 发布:视听语言 知乎 编辑:程序博客网 时间:2024/05/16 14:35

1.为什么会有智能指针?

因为存在下面的一些尴尬情况:

(1)申请动态内存时,new完忘了写delete。如果程序规模比较大,则很难检查出这个错误。导致内存泄露,程序发生莫名其妙的问题。

(2)我们定义a指针指向某对象,然后定义b也指向该对象。此时只是指针的拷贝,对象数据只有一份。当我们通过b释放了该对象时,a指针就变成悬空指针。其危险性和未初始化的指针一样。

(3)避免悬空指针的一个办法是在复制时采用深度复制,即不仅复制指针,而且将指针所指对象也拷贝一个副本。各管各的,互不干扰。但是这样代价太大。

(4)我们希望有一种聪明的指针,可以根据情况自行对上面各种问题作出反应。于是又了智能指针。

2.智能指针的机理

(1)C++98中定义有auto_ptr。C++11中新定义了shared_ptr,unique_ptr,weak_ptr等智能指针。设计采用“引用计数”的方式。即是否释放一个对象,根据是否有指针仍在引用它。如果有则不能释放,如果该对象上的引用计数为0,则系统自动回收。python和java中应该也是这种机理。

(2)于是我们将普通指针包装成一个类。该类中有一个引用计数。并且当新创建时计数为1。当销毁调用析构函数时,或者离开局部作用域时,计数减去1。当复制给另一个指针时,右侧计数加1,左侧计数减去1。这样上面的问题就可解决。

创建一个智能指针a(这里的a是一个智能指针对象)指向某个对象,则计数加1。创建一个b(a),则a,b的计数都将为2,因为giant对象上有2个指针同时指向着。当b=a时,重载=运算符,此时a的计数加1,b的原对象上计数减去1,然后b的计数与a相同。

(3)智能指针的使用,保证系统能够自动回收没人指向的内存,避免内存泄露,把人的因素降到最低。因此《c++ primer》讲到此处作者强烈建议使用智能指针。

3.智能指针实现的示例代码

// shared_ptr.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include <iostream>using namespace std;//被操作的基础类class Point {public:    Point(int xval = 0, int yval = 0) :x(xval), y(yval) {}    int getX() const { return x; }    int getY() const { return y; }    void setX(int xval) { x = xval; }    void setY(int yval) { y = yval; }private:    int x, y;};//辅助类,每个基础类的对象上都绑定的计数器class refPtr {    friend class SmartPtr;    refPtr(Point *ptr) :p(ptr), count(1) {}    ~refPtr() { delete p; }    //计数器    int count;    //指向所绑定的基础类的某个对象    Point *p;};//类似shared_ptr的my智能指针类class SmartPtr {public:    void print() const { cout << rp->count; }    SmartPtr() = default;    //当创建一个智能指针,指向基础类的某个对象时    //会调用计数器类的构造函数,生成一个计数器对象绑定到基础类的对象上    //此时智能指针对象->计数器类对象->基础类对象    SmartPtr(Point *ptr) :rp(new refPtr(ptr)) {}    //copy constructor    //源指针和目的指针,指向同一计数器对象    //把计数器对象中的数+1    SmartPtr(const SmartPtr &sp) :rp(sp.rp) { ++rp->count; }    //b=a,拷贝赋值运算符    //首先把右侧指针指向的计数器中的计数+1    //左侧指针指向的计数器中的计数-1,判断是否为0,是则销毁该对象    //让左侧指针指向右侧的计数器    SmartPtr & operator=(const SmartPtr &rhs) {        ++rhs.rp->count;        if (--rp->count == 0)            delete rp;        rp = rhs.rp;        return *this;    }    //每个智能指针析构时,都将指向的计数器-1,判断是否需要销毁    ~SmartPtr() {        if (--rp->count == 0)            delete rp;    }private:    refPtr *rp;};int main(){    Point a(3, 4);    Point * p1 = &a;    cout << p1->getX() << endl;    SmartPtr p2(p1);    p2.print();    //SmartPtr p3(p2);    //p2.print();    //p3.print();    return 0;}
原创粉丝点击