智能指针

auto_ptr

概念

  • auto_ptr是C++标准中的智能指针,在指针退出作用域的时候自动释放指针指向的内存,即使是异常退出的时候。
  • auto_ptr实际上是一个对象,重载了operator*和operator->,且提供了一些成员函数,比如使用成员get()可以获得对应类型的原始指针。
  • auto_pt的特点是可以对其进行复制和赋值,但同一时刻只能有一个auto_ptr管理指针。

使用

    std::auto_ptr<int> ap1(new int(5));
    cout << *ap1 << endl;

    int* p = ap1.get();
    cout << *p << endl;

    std::auto_ptr<int> ap2(ap1);//ap1失去管理权,不再拥有指针,ap2得到管理权
    assert(ap1.get() == 0);//get()获得的指针为空

scoped_ptr

概念

  • boost的scoped_ptr用法类似于auto_ptr,都不能用作容器的元素,不支持++、–等指针算数操作。
  • scoped_ptr的特点是拷贝构造函数和赋值操作符都是私有的,所以scoped_ptr不能进行复制和赋值操作,保证了对对象的唯一管理权。

使用

    boost::scoped_ptr<int> sp1(new int(10));
    boost::scoped_ptr<int> sp2(sp1);//编译无法通过:不能转让sp1的管理权到sp2
    boost::scoped_ptr<int> sp3(new int(30));
    sp3 = sp1;//编译无法通过:不能转让sp1的管理权到sp3

scoped_array

使用

#include <boost/scoped_array.hpp> 

int main() 
{ 
  boost::scoped_array<int> i(new int[2]); 
  *i.get() = 1; 
  i[1] = 2; 
  i.reset(new int[3]); 
    
    boost::scoped_array<Book> myBook(new Book[2]);
    myBook.reset(new Book[3]);
} 
=====exp_test_scoped_array=====
Creating book ...
Creating book ...
Creating book ...
Creating book ...
Creating book ...
Destroying book ...
Destroying book ...
Destroying book ...
Destroying book ...
Destroying book ...
=====exp_test_scoped_array=====

shared_ptr

概念

  • shared_ptr没有scoped_ptr的限制,它可以被自由的拷贝和赋值,也可以作为容器的元素。它是一种引用计数型的智能指针,当没有代码使用它时,即引用计数为0的时候自动删除动态分配的内存。
  • shared_ptr也支持*和->操作符,支持==比较操作(相当于a.get() == b.get()),提供隐式bool类型转换以判断指针的有效性,同样不提供指针的算数运算。
  • shared_ptr中的一些成员函数:
  • get():获取内部原始指针。
  • reset():重置shared_ptr,会导致引用计数减1。不带参数的reset()将shared_ptr重置为不指向任何对象,带参数的reset()用来将shared_ptr重置为指向新的对象。
  • unique():用来检测当前是不是指针的唯一管理者,即引用计数为1。
  • use_count():用来获取当前引用计数,但它一般在调试中使用,因为其效率很低,如果只是判断当前引用计数是否为1的话可以使用unique()来替换它。
  • 将shared_ptr赋值为nullptr相当于调用reset()。
  • shared_ptr也提供了转换运算符dynamic_pointer_cast<>、static_pointer_cast<>、const_pointer_cast<>。

使用

#include <boost/shared_ptr.hpp>
void exp_test_shared_ptr()
{

	  boost::shared_ptr<Book> myBook(new Book(101));
	  cout<<myBook.use_count()<<endl;
	  boost::shared_ptr<Book> myBook2(myBook);
	  cout<<myBook->m_id<<endl;//101
	  cout<<myBook2->m_id<<endl;//101

/*	  cout<<myBook.use_count()<<endl;//2
	  cout<<myBook2.use_count()<<endl;//2
	  myBook.reset();//
	  cout<<myBook.use_count()<<endl;//0
	  cout<<myBook2.use_count()<<endl;//1
	  myBook2.reset();
	  cout<<myBook.use_count()<<endl;//0
	  cout<<myBook2.use_count()<<endl;//0
*/
    /*
	  myBook.reset(new Book(102));
	  cout<<myBook.use_count()<<endl;//1
	  cout<<myBook2.use_count()<<endl;//1
	  cout<<myBook->m_id<<endl;//102
	  myBook.reset();
	  cout<<myBook2->m_id<<endl;//
	  */

}

shared_array

使用

#include <boost/shared_array.hpp>
void exp_test_shared_array()
{
	boost::shared_array<Book> myBook(new Book[2]);
	boost::shared_array<Book> myBook2(myBook);
	myBook[0].m_id = 101;
	std::cout << myBook[0].m_id << std::endl;
	std::cout << myBook2[0].m_id << std::endl;
	std::cout << myBook[1].m_id << std::endl;
	std::cout << myBook2[1].m_id << std::endl;
}

weak_ptr

概念

  • 首先 boost::weak_ptr是专门为boost::shared_ptr而准备的。
  • boost::weak_ptr是 boost::shared_ptr的观察者(Observer)对象
  • 观察者意味着boost::weak_ptr只对boost::shared_ptr进行引用,而不改变其引用计数。
  • 当被观察的boost::shared_ptr失效后,相应的boost::weak_ptr也随之失效。
  • 一个强引用是指当被引用的对象仍活着的话,这个引用也存在(也就是说,只要至少有一个强引用,那么这个对象就不会也不能被释放)。boost::share_ptr就是强引用。
  • 相对而言,弱引用当引用的对象活着的时候不一定存在。仅仅是当它自身存在的时的一个引用。
  • 弱引用并不修改该对象的引用计数,这意味这弱引用它并不对对象的内存进行管理。
  • 在功能上类似于普通指针,然而一个比较大的区别是,弱引用能检测到所管理的对象是否已经被释放,从而避免访问非法内存。

使用

class Teacher
{
 
public:
	shared_ptr<Student> m_pStudent;
};
 
class Student
{
 
public:
	weak_ptr<Teacher> m_pTeacher;
};
 
int main()
{
	shared_ptr<Teacher> pTeacher(new Teacher);
	shared_ptr<Student> pStudent(new Student);
	pTeacher->m_pStudent = pStudent;
	pStudent->m_pTeacher = pTeacher;
}

make_shared

工厂函数

概念

  • 当shared_ptr的构造参数是一个new操作符的时候,虽然我们不用手动调用delete来释放它,可这导致了代码中的某种不对称性,所以应该使用工厂模式来解决:
  • 头文件"boost/make_shared.hpp"中提供了一个自由工厂函数make_shared()来消除显示的new操作,它可以返回一个shared_ptr对象,使用示例:

使用

#include "boost/smart_ptr.hpp"
#include "boost/make_shared.hpp"
#include <vector>

int main()
{
    boost::shared_ptr<string> sp = boost::make_shared<string>("make_shared");
    boost::shared_ptr<std::vector<int>> spv = boost::make_shared<std::vector<int>>(10, 2);
    assert(spv->size() == 10);

    return 0;
}

删除器

概念

  • shared_ptr默认使用delete释放它指向的对象,我们可以通过使用其另一种构造方法来指定其他的释放操作。

  • shared_ptr有一种特殊形式的构造函数:shared_ptr(T* p, D d); 这里边的d就是删除器,它可以是一个函数对象或函数指针。

  • 删除器用来指定shared_ptr在析构的时候即离开作用域的时候不是执行释放内存的操作,而是执行d函数。函数get_deleter()可以获得删除器指针。

使用

class CSock
{
    ...
};

CSock* open_sock()
{
    CSock* s = new CSock;
    ...//do some open job
    
    return p;
}

void close_sock(CSock* s)
{
    ...//do some close job
    delete s;
}

boost::shared_ptr(CSock*)(open_sock(), close_sock);