智能指针是行为类似于普通指针的类对象,它通常用来帮助管理动态内存问题。比如说,我们在一个函数里,使用了 new 分配了一块内存,但忘记在函数返回时使用 delete 收回内存,从而导致了内存泄露。对于这种问题,尽管我们可以提醒自己要记得去收回内存,但总是难以避免由于这样那样的原因而忘记或不小心造成内存的泄露。
假设指向分配内存的是一个对象而不是单纯一个常规指针,那么在该对象过期时,让它的析构函数删除指向的内存,那就可以解决上述的“遗忘”问题了。这正是智能指针 auto_ptr,unique_ptr 和 shared_ptr 提出的思想。
auto_ptr 是 C++98 提供的解决方案,但在 C++11 里已经摒弃,并提供了两外两种解决方案。然而,虽然 auto_ptr 已经被摒弃,但它使用了多年,同时还有可能有的编译器不支持其它两种解决方案,auto_ptr 将是唯一的选择。
要创建智能指针对象,必须包含头文件 memory,该文件包含了智能指针的模板定义,比如对于 auto_ptr 的模板包含如下构造函数:
[C++] 纯文本查看 复制代码 template <class X>
class auto_ptr {
public:
typedef X element_type;
// 20.4.5.1 construct/copy/destroy:
explicit auto_ptr(X* p =0) throw();
auto_ptr(auto_ptr&) throw();
template <class Y> auto_ptr(auto_ptr<Y>&) throw();
auto_ptr& operator=(auto_ptr&) throw();
template <class Y> auto_ptr& operator=(auto_ptr<Y>&) throw();
auto_ptr& operator=(auto_ptr_ref<X>) throw();
~auto_ptr() throw();
// 20.4.5.2 members:
X& operator*() const throw();
X* operator->() const throw();
X* get() const throw();
X* release() throw();
void reset(X* p =0) throw();
// 20.4.5.3 conversions:
auto_ptr(auto_ptr_ref<X>) throw();
template <class Y> operator auto_ptr_ref<Y>() throw();
template <class Y> operator auto_ptr<Y>() throw();
};
}
在 explicit auto_ptr(X* p =0) throw(); 这个构造函数中,使用了异常规范的语法,throw() 中没有指定任何异常,也就意味着该构造函数不会引发异常。
比如获得一个指向 double 和 string 类型的 auto_ptr :- auto_ptr<double> pd (new double);
- auto_ptr<string> ps (new string);
复制代码 new double 是 new 返回的指针,指向新分配的内存块,它是构造函数 auto_ptr<double> 的参数,也就是函数原型中形参 p 的实参;同样,new string 也是构造函数的参数。与 auto_ptr 类似,shared_ptr 和 unique_ptr 也有同样的语法:- unique_ptr<double> pud (new double);
- shared_ptr<string> pss (new string);
复制代码 下面程序中演示了如何使用这 3 种智能指针。在编译时,需要编译器支持 C++11 新增的类 shared_ptr 和 unique_ptr 。每个智能指针都放在一个代码块内,当离开代码块时,指针过期。Report 类报告对象的创建和销毁。
[C++] 纯文本查看 复制代码 // smrtptrs.cpp -- using three kinds of smart pointers
#include <iostream>
#include <string>
#include <memory>
class Report
{
private:
std::string str;
public:
Report(const std::string s) : str(s) { std::cout << "Object created!\n"; }
~Report() { std::cout << "Object deleted!\n"; }
void comment() const { std::cout << str << "\n"; }
};
int main()
{
{
std::auto_ptr<Report> ps (new Report("using auto_ptr"));
ps->comment(); // use -> to invoke a member function
}
{
std::shared_ptr<Report> ps (new Report("using shared_ptr"));
ps->comment();
}
{
std::unique_ptr<Report> ps (new Report("using unique_ptr"));
ps->comment();
}
// std::cin.get();
return 0;
}
运行结果:
考虑一下几种赋值方式:- shared_ptr<double> pd;
- double *p_reg = new double;
- pd = p_reg; // 不允许,普通指针到智能指针的隐式转换
- pd = shared_ptr<double>(p_reg); // 可以,显示转换
- shared_ptr<double> pshared = p_reg; // 不允许,隐式转换
- shared_ptr<double> pshared(p_reg); //允许,显示转换
复制代码 不论使用哪一种智能指针,都要注意避免下面的情况:- string vacation ("I wanted lonely as a cloud.");
- shared_ptr<string> pavc(&vacation); // 不能这么做!
复制代码 不能这么做的原因是,当 pavc 过期时,程序将用 delete 用于非堆运算符(vacation 在栈中分配),这是错误的。
|