C++面试中关于智能指针的问题

1、 什么是智能指针?
2、 分析下常见的智能指针有哪些?
3、实现一个智能指针呗?(没具体说写哪个,建议默认写:unique_ptr)
1、答:智能指针(smart pointer)是存储指向动态分配(堆)对象指针的类,用于生存期控制,能够确保自动正确的销毁动态分配的对象,防止内存泄露(利用自动调用类的析构函数来释放内存)。它的一种通用实现技术是使用引用计数(除此之外还有资源独占,如(auto_ptr),只引用,不计数(weak_ptr))。智能指针类将一个计数器与类指向的对象相关联,引用计数跟踪该类有多少个对象共享同一指针。每次创建类的新对象时,初始化指针并将引用计数置为1;当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数;对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数为减至0,则删除对象),并增加右操作数所指对象的引用计数;调用析构函数时,构造函数减少引用计数(如果引用计数减至0,则删除基础对象)。

2、常见的智能指针以及解析:

auto_ptr
(1)它是C++标准库提供的类模板,auto_ptr对象通过初始化指向由new创建的动态内存,它是这块内存的拥有者,一块内存不能同时被分给两个拥有者(资源独占)。当auto_ptr对象生命周期结束时,其析构函数会将auto_ptr对象拥有的动态内存自动释放。
(2)auto_ptr不能指向数组,因为auto_ptr在析构的时候只是调用delete,而数组应该要调用delete[]。(但uniquearray管理的是一段连续的空间,它也是防拷贝的,功能类似于vector。)
(3)auto_ptr不能作为容器对象,因为它不支持拷贝构造与赋值(出错了也不容易发现),STL容器中的元素经常要支持拷贝,赋值等操作,在这过程中auto_ptr会传递所有权,那么就会出错。

unique_ptr
它是( C++11引入的,前身是scoped_ptr,scoped_ptr是boost库里的),也不支持拷贝构造和赋值,但比auto_ptr好,直接赋值会编译出错(与auto_ptr最大的不同就是类内私有的声明了拷贝构造函数和赋值运算符重载,是针对auto_ptr的缺点而出现的)。

shared_ptr
C++11或boost的shared_ptr,基于引用计数的智能指针。可随意赋值,直到内存的引用计数为0的时候这个内存会被释放。环状的链式结构可能会形成内存泄露(循环引用)
循环引用问题(常问到哦)
C++面试中关于智能指针的问题_第1张图片

C++11或boost的weak_ptr,弱引用。 引用计数有一个问题就是互相引用形成环,这样两个指针指向的内存都无法释放。需要手动打破循环引用或使用weak_ptr。顾名思义,weak_ptr是一个弱引用,它是为了配合shared_ptr而引入的一种智能指针,它指向一个由shared_ptr管理的对象而不影响所指对象的生命周期,也就是说,它只引用,不计数。如果一块内存被shared_ptr和weak_ptr同时引用,当所有shared_ptr析构了之后,不管还有没有weak_ptr引用该内存,内存也会被释放。所以weak_ptr不保证它指向的内存一定是有效的,在使用之前需要检查weak_ptr是否为空指针。

weak_ptr并没有重载operator->和operator *操作符,因此不可直接通过weak_ptr使用对象,典型的用法是调用其lock函数来获得shared_ptr示例,进而访问原始对象。

auto_ptr的实现

template
class Autoptr //采用资源的转移方法管理内存,在它的拷贝构造和赋值运算符引起会出现问题
{
public:
    Autoptr(T *p=NULL )
        :ptr(p)
    {}
    Autoptr(Autoptr&ap)
        :ptr(ap.ptr)
    {
        ap.ptr= NULL;//新对象构造成功之后,原来对象指针为NULL;保证free的时候释放1次

    }

    Autoptr&operator=(Autoptr&ap)
    {
        if(this!= &ap)
        {
            if(ap.ptr)
            {
                deleteptr;
            }
            ptr= ap.ptr;
            ap.ptr= NULL;
        }
        return*this;
    }

    T* operator*()
    {
        return*ptr;
    }
    T* operator->()
    {
        returnptr;
    }
    voidget_ptr()
    {
        returnptr;
    }
    ~Autoptr()
    {
        if(ptr)
        {
            deleteptr;
            ptr= NULL;
        }
    }
private:
    T*ptr;
};
voidfuntest()
{
    int*p = new int(1);
    Autoptr<int>ap1(p);   //只是调了构造函数,没有调拷贝构造函数
    Autoptr<int>ap2(ap1);//调了拷贝构造函数,ap1=NULL;
    Autoptr<int>ap3;
   ap3= ap2;//赋值不过去,因为两个对象地址不同,ap2.ptr也不为空,所以调用operator=函数,但是此刻已经释放了
}            //ap3的ptr指向的空间,所以没法向ap3赋值
int main()
{
    funtest();
    system("pause");
    return0;
}
unique_ptr的实现
template
class unique_ptr //前身是scoped_pt,实现粗暴—>禁止转移-->独占资源(只允许一个指针管理资源)
                //(禁止调拷贝构造和赋值运算符),它只能管理单个对象
{
public:
    unique_ptr (T*p = NULL)
        :ptr(p)
    {}


    T* operator*()
    {
        return*ptr;
    }
    T* operator->()
    {
        returnptr;
    }
    voidget_ptr()
    {
        returnptr;
    }
    ~ unique_ptr ()
    {
        if(ptr)
        {
            deleteptr;
            ptr= NULL;
        }
    }
private:
    unique_ptr (unique_ptr &ap);//禁止拷贝构造
    unique_ptr &operator=( unique_ptr &ap1);//禁止赋值
    T*ptr;
};
//为什么unique_ptr防拷贝的实现必须是私有的声明?
1、只给共有的声明,不给定义。(用户可以在类外重新给出定义)
2、只给私有的定义(但是类内可以调拷贝构造和赋值运算符)
所以采用私有的声明拷贝构造函数和赋值运算符重载函数实现unique_ptr的防拷贝
shared_ptr的实现
template
class Share_Ptr
{
public:
    Share_Ptr(T*p = NULL)
        :_p(p)
        ,_pcount(NULL)
    {
        if(NULL != _p)
        {
            _pcount= new int(1);//构造成功时有一个对象用,初始化为1
        }
    }

    Share_Ptr(const Share_Ptr&ps)
        :_p(ps._p)
        ,_pcount(ps._pcount)
    {
        if(NULL != _pcount)
        {
            ++*_pcount;
        }
    }

    T* operator*()
    {
        return*_p;
    }
    T* operator->()
    {
        return_p;
    }
    voidget_ptr()
    {
        return_p;
    }

    ~Share_Ptr()
    {
        if(NULL!=_pcount&&0 ==*(--_pcount))
        {
            delete_pcount;
            _pcount= NULL;
            delete_p;
            _p= NULL;
        }
    }
private:
    T* _p;
    int*_pcount;
};

voidFunTest()
{
    Share_Ptr<int>ps1(new int);//ps1->_pcount=1;
    Share_Ptr<int>ps2(ps1);//ps2->_pcount=2;
    Share_Ptr<int>ps3;
    ps3= ps2;//ps3->_pcount=2;
}

你可能感兴趣的:(C++,智能指针)