分类:c++| 发布时间:2015-09-18 23:10:00
原文: http://cs-cjl.com/2015/09_18_cpp_smart_pointer_02
更通用的智能指针
在上一节中,我们给出了一个智能指针的简单实现,但是这个实现有一个严重的问题,
它只能保存 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();
}