码迷,mamicode.com
首页 > 编程语言 > 详细

【C++】智能指针

时间:2015-05-11 09:00:53      阅读:134      评论:0      收藏:0      [点我收藏+]

标签:

            本节研究智能指针的相关问题;


unique_ptr的简单实现

template <typename T>  
class SmartPointer  
{  
public:  
  SmartPointer(const SmartPointer&) = delete;  
  SmartPointer& operator=(const SmartPointer&) = delete;  
  
  explicit SmartPointer(T* p= NULL)  
      :_pointer(p)  
  {  
  
  }  
  
  ~SmartPointer()  
  {  
    delete _pointer;  
  }  
  
  T* operator->() const  
  {  
    return _pointer;  
  }  
  
  T& operator*() const  
  {  
    return *_pointer;  
  }  
  
  T* get() const  
  {  
    return _pointer;  
  }  
  
  T* release()  
  {  
    T* p = _pointer;  
    _pointer = NULL;  
    return p;  
  }  
  
  void reset(T* p = NULL)  
  {  
    if (p !=  _pointer)  
      {  
        delete _pointer;  
        _pointer = p;  
      }  
  }  
private:  
  T* _pointer;  
};  
说明几点:

(1)SmartPointer类似unique_ptr一样,不支持拷贝构造和赋值,是对auto_ptr的加强版;

原始指针

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

int main(void)
{
  vector<int*> v;
  {
    int x = 10;
    v.push_back(&x);
    v.push_back(new int(2));
  }

  cout << v[0] << " "<< v[1] << endl;
  cout << *v[0] << " "<< *v[1] << endl;
}

说明几点:

(1)当v离开块作用域(两次push_back所在的作用域时),对v[0]的访问将会是非法指针访问;栈对象已经析构,v[0]所访问的内存的内容已经不存在虽然本题输出仍正确,因为x变量所在的内存未被重新利用;

(2)当v离开main作用域时,v发生了内存泄露,需要显式delete,因为原始指针(包括类的原始指针)和int,long long这样的基本数据类型一样,不会执行析构函数,内存泄漏;而要自己显示执行delete v[0]; 


原始指针对象

代码片段如下:

#include <iostream>
#include <vector>
#include <utility>
using namespace std;

class A
{
public:
  A() = default;

  A(const A& a)
  {
    cout << "copy ctor" << endl;
  }

  A(A&& a) noexcept
  {
    cout << "move ctor" << endl;
  }
};

int main(void)
{

  vector<A> rawVec;
  rawVec.reserve(10);

  cout << "------------------\n";
  rawVec.push_back(A());


  cout << "------------------\n";
  rawVec.push_back(*(new A()));

  cout << "------------------\n";
  rawVec.push_back(std::move(*(new A())));
}

说明几点:

(1)rawVec.push_back(A());首先产生一个临时对象,由于A提供了移动构造函数,容器将直接调用移动构造函数;然后临时对象自动销毁;

(2)push_back(*(new A());首先new int()创建了一个堆内存,然后解引用将其拷贝构造到vector中,vector本身的管理数据在栈内存中,而真正的数据也在堆内存中,由stl的空间配置器分配);push_back(*(new A())将会内存泄漏,因为push_back()中放入的对象是拷贝的新对象,而最后离开main函数后,vector销毁该对象时,析构的也是该新对象,原有堆内存对象不会析构,内存泄漏

(3)push_back(std::move(*(new A())));首先new int()创建了一个堆内存,然后解引用并使用std::move将其移动构造到vector中,然而new A()本身所占用的内存(管理)将会泄漏;

(4)当rawVec离开main作用块时,会对其每一个对象调用析构函数;

(5)因为A()移动构造并未做任何事情,下面以A为string作为替换,假设string实现移动构造函数,而字符串值作为移动构造函数进行提高效率的关键部分;

(5.1)对于rawVec.push_back(string("123")); rawVec将会使用移动构造接管“123”的内存,而本身string临时对象的管理数据将会自动销毁; 

(5.2)对于rawVec.push_back(*(new string("123")));rawVec将会使用拷贝构造复制“123”的内存,而new string("123")的管理数据以及"123"都将会泄露;

(5.3)对于rawVec.push_back(std::move(*(new string("123"))));rawVec将会使用移动构造接管“123”的内存,而new string("123")的管理数据会泄露,“123”本身不会泄露,而被vector中的对象接管;


shared_ptr产生

   std::shared_ptr<int> p1 = std::make_shared<int>();
   std::shared_ptr<int> p2(new int);
说明几点:

(1)在shared_ptr中,管理信息至少包括一个引用计数count和一个指向对象的指针;对于p1的产生,new int和管理信息的内存是一次性申请出来的;

(2)而p2的产生,首先会先new一个int,然后再申请管理信息的内存,总共会有两次内存申请;当涉及到多个std::shared_ptr<int> p(new int)对象分配时,可能会导致内存泄露;

shared_ptr二次释放问题

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

class A
{
public:
  A() = default;

  ~A()
  {
    cout << "dtor" << endl;
  }
};

void fun(shared_ptr<A> a)
{
}

int main(void)
{
  A *x(new A);

  fun(shared_ptr<A>(x));
  cout << "-------------\n";

  shared_ptr<A> p(x);
}

说明几点:

(1)fun()中shared_ptr已经接管了x所指向的堆内存,并将释放;而 当shared_ptr<A> p(x);接管的x指向内存已经释放,造成二次释放,造成段错误;
(2)使用shared_ptr的get()的原始指针,也有可能出现二次释放的问题;因为对get()原始指针进行shared_ptr将会单独创建,而不是共享;


shared_ptr构造删除器

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

class A
{
public:
  A() = default;

  ~A()
  {
    cout << "dtor" << endl;
  }
};

int main(void)
{
  A *x(new A[10]);
  shared_ptr<A>  a(x , [](A *p)
  {
    delete []p;
  } );
}
说明几点:

(1)因为shared_ptr不直接支持动态数组,默认的删除器是delete p;因此需要显式传入删除器;
(2)栈对象有时也可以需要shared_ptr来管理,显然我们不能使用默认的删除器,也需要传入删除器;


unique_ptr内存泄露

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

class A
{
public:
  A() = default;

  ~A()
  {

    cout << "dtor" << endl;
  }
};

int main(void)
{
  unique_ptr<A> a(new A);
  a.release();

  unique_ptr<A[]> b(new A[1]);
  b.reset();
}
说明几点:

(1)a.realase()将会转换对指针的控制权,但是如果没有新的unique_ptr接管,那么将会存在内存泄露,应该使用reset进行显式的内存释放;

(2)a所管理的内存,release()将会内存泄露;而b.reset将会显式释放控制,并销毁内存;

(3)unique_ptr不同于shared_ptr,直接支持动态数组;

【C++】智能指针

标签:

原文地址:http://blog.csdn.net/skyuppour/article/details/45626507

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!