分类:c++| 发布时间:2015-09-18 23:10:00
在上一节中,我们给出了一个智能指针的简单实现,但是这个实现有一个严重的问题, 它只能保存 some_type 类型的指针。 如何实现一个更加通用的智能指针呢? 通过使用模板可以简单地实现这一目的:
template<typename T>
class smart_ptr
{
public:
explicit smart_ptr(T *p): p_(p) {}
~smart_ptr() {
clean();
}
void reset(T *p) {
if (p_ == p)
return;
clean();
p_ = p;
}
void clean() {
if (p_) {
delete p_;
p_ = 0;
}
}
private:
T *p_;
};
bool some_func()
{
smart_ptr<int> int_p;
smart_ptr<some_type> some_type_p;
{
some_type *tmp = new some_type();
if (!tmp)
return false;
some_type_p.reset(tmp);
}
{
int *tmp = new int(3);
if (!tmp)
return false;
int_p.reset(tmp);
}
// do something
if (failed) {
// Ok, it will delete auto
return false;
}
return true;
}
可以看到,使用了模板之后 smart_ptr 可以保存任意类型的指针, 所需要做的改变只是在尖括号内给出指针的类型(如 auto_ptr 等标准实现一样)。
在上面的例子中,通过我们实现的智能指针可以确保在函数结束时释放内存。 但上面的实现缺少一个非常重要的功能,先来看一个例子:
int *make_int()
{
int *tmp = new int(3);
if (!tmp)
return 0;
if (failed)
return 0;
return tmp;
}
bool some_func()
{
smart_ptr<int> int_p(make_int());
if (int_p is null)
return false;
// set int to 4
// Oops: not way to do it
return true;
}
在上面的例子中,我们想要将 4 赋给 int_p 指向的值。 却发现没有方法或者 int_p 包含的原始指针,我们需要添加一个方法以返回它的原始指针。
template<typename T>
class smart_ptr
{
public:
// See other impl above
T* get() {
return p_;
}
private:
T *p_;
};
// see make_int above
bool some_func()
{
smart_ptr<int> int_p(make_int());
if (!int_p.get())
return false;
// set int to 4
(*int_p.get()) = 4;
return true;
}
我们添加了一个返回原始指针 get() 方法使得可以操作原始指针。 (事实上,在所有的智能指针实现中都会添加这么一个方法。)
假设我们的函数 some_func 需要将 int_p 拥有的原始指针返回,我们应该怎么做呢? 直接通过 get() 获取原始指针然后返回?
int* some_func()
{
smart_ptr<int> int_p(make_int());
if (!int_p.get())
return 0;
// set int to 4
(*int_p.get()) = 4;
return int_p.get();
}
上述代码会不会有问题呢? 当 some_func 结束时,int_p 的生命周期也结束了,这是他的析构函数会 delete 掉它本身 所拥有的原始指针。因此,some_func 会返回一个无效的指针。
我们需要一个函数在返回原始指针的同时,放弃对原始指针的所有权。 这个函数通常被命名为 release() 。
template<typename T>
class smart_ptr
{
public:
// See other impl above
T* release() {
T* tmp = p_;
p_ = 0;
return tmp;
}
private:
T *p_;
};
int* some_func()
{
smart_ptr<int> int_p(make_int());
if (!int_p.get())
return 0;
// set int to 4
(*int_p.get()) = 4;
return int_p.release();
}