智能指针
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);