看完这篇,别再说不会智能指针了

一、智能指针的作用

智能指针的作用

智能指针的作用 :智能指针可以帮助我们避免在申请空间后忘记释放造成内存泄漏的问题;因为智能指针本身是一个类(后面也会自己实现一下),当出了类的作用域的时候,类会调用析构函数进行释放资源。所以智能指针的作用原理就是在函数结束时自动释放内存空间,不需要手动释放内存空间。

二、智能指针的原理

我们这里的指针指针主要指的是 shared_ptr ,这也是一种 引用计数型智能指针 ,引用计数顾名思义就是在内存中记录有多少个智能指针被引用,新增一个引用计数加一,过期引用计数则减一,当引用计数为0的时候,

智能指针才会释放资源;

案例一

#include <iostream>
#include <memory>

using namespace std;

class A
{
public:
 A()
 {
  cout << "A Constructor" << endl;
 }
 ~A()
 {
  cout << "A Destruct" << endl;
 }
};



int main()
{
 shared_ptr<A> p = make_shared<A>();
 cout << "count:"<<p.use_count() << endl;
 return 0;
}

 

结果:

root@iZuf67on1pthsuih96udyfZ:~/C++/Net_C++/demo4# ./test1 
A Constructor
count:1
A Destruct

 

我们再增加一个传参,看一下引用计数:

案例二

#include <iostream>
#include <memory>

using namespace std;

class A
{
public:
 A()
 {
  cout << "A Constructor" << endl;
 }
 ~A()
 {
  cout << "A Destruct" << endl;
 }
};

void fun(shared_ptr<A>p)
{   
    cout<<"fun count:"<<p.use_count()<<endl;
}

int main()
{
 shared_ptr<A> p = make_shared<A>();
 cout << "count:"<<p.use_count() << endl;
    fun(p);
    cout << "count:"<<p.use_count() << endl;
 return 0;
}

 

结果:

root@iZuf67on1pthsuih96udyfZ:~/C++/Net_C++/demo4# ./test1 
A Constructor
count:1
fun count:2
count:1
A Destruct

 

通过上面的两个例子,我们验证了最开始说的: 智能指针本身是一个类(后面也会自己实现一下),当出了类的作用域的时候,类会调用析构函数进行释放资源;

三、智能指针的使用

智能指针的使用比较简单,在我们程序中需要包含头文件:

#include <memory>

 

注意:智能指针是 C++11 的标准,在编译的时候需要加上 -std=c++11 的编译参数;

使用智能指针初始化有几种方式, new 和 make_shared ,这里推荐使用 make_shared ,原因是: make_shared 标准库函数,是最安全的分配和使用动态内存的方法,此函数在动态内存中分配一个对象并初始化它,返回指向此对象的 shared_ptr ;头文件和 share_ptr 相同。

简单给个案例:

案例三

#include <iostream>
#include <memory>

using namespace std;

class A
{
public:
    A(int count)
    {
        _nCount = count;
    }
    ~A(){}
    void Print()
    {
        cout<<"count:"<<_nCount<<endl;
    }
private:
    int _nCount;
};

int main()
{   
    shared_ptr<A>p = make_shared<A>(10);
    p->Print();
    return 0;
}

 

编译过程;

root@iZuf67on1pthsuih96udyfZ:~/C++/Net_C++/demo4# g++ -std=c++11 test2.cpp -o test2
root@iZuf67on1pthsuih96udyfZ:~/C++/Net_C++/demo4# ./test2
count:10

 

四、智能指针使用注意项

我们先来看一段代码:

案例四

#include <iostream>
#include <memory>

using namespace std;

class B;

class A
{
public:
    shared_ptr<B>_pb;
};

class B
{
public:
    shared_ptr<A>_pa;
};

int main()
{
    shared_ptr<A>pa = make_shared<A>();
    shared_ptr<B>pb = make_shared<B>();
    cout<<"pa count:"<<pa.use_count()<<endl;
     cout<<"pb count:"<<pb.use_count()<<endl;
    pa->_pb = pb;
    pb->_pa = pa;
    cout<<"pa count:"<<pa.use_count()<<endl;
    cout<<"pb count:"<<pb.use_count()<<endl;
    return 0;
}

 

结果;

root@iZuf67on1pthsuih96udyfZ:~/C++/Net_C++/demo4# g++ -std=c++11 test3.cpp -o test3
root@iZuf67on1pthsuih96udyfZ:~/C++/Net_C++/demo4# ./test3
pa count:1
pb count:1
pa count:2
pb count:2

 

会发现,最终的引用计数为2,那么结束后,引用计数不为0,他们在堆上的空间不会被释放,这就是常说的 循环引用 ;

当然,这不是无解的,我们可以另外一种只能指针,只不过这是种弱指针--- weak_ptr ,这种指针不会增加引用计数,配合 shared_ptr ,可谓是郎才女貌,皆大欢喜呀!

案例五

#include <iostream>
#include <memory>

using namespace std;

class B;

class A
{
public:
    weak_ptr<B>_pb;
};

class B
{
public:
    weak_ptr<A>_pa;
};

int main()
{
    shared_ptr<A>pa = make_shared<A>();
    shared_ptr<B>pb = make_shared<B>();
    cout<<"pa count:"<<pa.use_count()<<endl;
     cout<<"pb count:"<<pb.use_count()<<endl;
    pa->_pb = pb;
    pb->_pa = pa;
    cout<<"pa count:"<<pa.use_count()<<endl;
    cout<<"pb count:"<<pb.use_count()<<endl;
    return 0;
}

 

结果:

root@iZuf67on1pthsuih96udyfZ:~/C++/Net_C++/demo4# g++ -std=c++11 test3.cpp -o test3
root@iZuf67on1pthsuih96udyfZ:~/C++/Net_C++/demo4# ./test3
pa count:1
pb count:1
pa count:1
pb count:1
 

很清晰的发现,在最后互相引用的时候,引用计数器没有加一,最后出作用域的时候就会调用析构函数,进行内存释放;

五、智能指针的实现

实现智能指针,无论是在面试还是深刻理解智能指针方面,对我们帮助都是非常大的,理解了上面的原理,我们动手实现一个智能指针:

智能指针实现代码

#include <iostream>

using namespace std;

template<class T>
class SmartPoint
{
public:
 //构造函数
 SmartPoint(T* p=NULL)
 {
  _ptr = p;
  if (p != NULL)
  {
   _count = 1;
  }
  else
  {
   _count = 0;
  }
 }
 //析构函数
 ~SmartPoint()
 {
  if (--_count == 0)
  {
   delete _ptr;
  }
 }
 //拷贝构造函数
 SmartPoint(const SmartPoint& src)
 {
  if (this != &src)
  {
   _ptr = src._ptr;
   _count = src._count;
   _count++;
  }
 }

 //重载赋值操作符
 SmartPoint& operator=(const SmartPoint& src)
 {
  if (_ptr == src._ptr)
  {
   return *this;
  }
  if (_ptr)
  {
   _count--;
   if (_count == 0)
   {
    delete _ptr;
   }
  }
  _ptr = src._ptr;
  _count = src._count;
  _count++;
  return *this;
 }

 //重载操作符
 T* operator ->()
 {
  if (_ptr)
   return _ptr;
 }

 //重载操作符
 T& operator *()
 {
  if (_ptr)
   return *_ptr;
 }

 size_t use_count()
 {
  return _count;
 }
private:
 T* _ptr;
 size_t _count;

};

void Use(SmartPoint<char> p)
{
 int n = p.use_count();
}

int main()
{
 SmartPoint<char>sp1(new char);
 Use(sp1);
 SmartPoint<char>sp2(sp1);
 SmartPoint<char>sp3;
 sp3 = sp1;
 int n = sp1.use_count();
 return 0;
}

送大家一张后台开发相关面试知识点汇总脑图 这是片段:

为什么说C++太复杂?复杂的必要性是为什么?

 

 

大家可以加qun获取。

为什么说C++太复杂?复杂的必要性是为什么?
 

原文链接: https://www.cnblogs.com/AdBingo/p/12935865.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    看完这篇,别再说不会智能指针了

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/350145

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年3月2日 上午6:07
下一篇 2023年3月2日 上午6:07

相关推荐