首先我们面临的挑战是,声明堆中的数据需要我们用new关键字,直到我们显示调用了delete之后,它们才会被移除,但问题是,我们什么时候应该移除?如果调用语句在上下行中,我们自然知道如何移除。我们知道如果对象声明在堆中,那么在它离开它的作用域中的时候,可以自动释放,如果我们能够用栈对象来管理堆对象,在栈对象自动释放的时候,释放堆对象,就不需要显式调用delete语句了:
于是就有了下面的做法,应该不难理解:
template<class T>
class smart_ptr {
public:
smart_ptr(T* t = 0) { real_ptr = t; }
~smart_ptr() { delete real_ptr; }
T* operator ->() const { return real_ptr; }
T& operator *() const { return *real_ptr; }
private:
T* real_ptr;
};
我们希望我们的智能指针能够像指针一样地工作,但下面的工作方式似乎存在问题:
在普通的dumb指针中,以下行为是正确的:
void letUsGo(BaseClass* objPtr);
DerivedClass* derivedObjPtr2 = new DerivedClass();
letUsGo(derivedObjPtr2);
delete derivedObjPtr2;
但是,以下代码呢?
void letUsSmartGo(const smart_ptr<BaseClass>& objPtr);
smart_ptr<DerivedClass> smartDerivedObjPtr2(new DerivedClass());
// the smart_ptr<DerivedClass> is not inherited from the smart_ptr<BaseClass>
// the compiler can't find the class to cast it, so it must cause the error.
letUsSmartGo(smartDerivedObjPtr2);
下面的过程描述了这个变化所需要的一些支持:
1、error C2664: “letUsSmartGo”: 不能将参数 1 从“smart_ptr<T>”转换为“const smart_ptr<T> &”
2、smartDerivedObjPtr2的类型:
smart_ptr<DerivedClass> smartDerivedObjPtr2(new DerivedClass());
3、letUsSmartGo的声明:
void letUsSmartGo(const smart_ptr<BaseClass>&);
4、问题转化为,如何从smart_ptr<DerivedClass>到const smart_ptr<BaseClass>&的转变。
5、针对letUsSmartGo的声明,可以有的实参类型包括:
const smart_ptr<BaseClass>
smart_ptr<BaseClass>
假设存在以下类型 smart_derived_ptr : smart_ptr<BaseClass>,那么smart_derived_ptr也是可以被传递的。
6、这里存在这样一个问题:
new DerivedClass() 被传递给smartDerivedObjPtr2之后,smartDerivedObjPtr2就拥有了它的指针。如果从smartDerivedObjPtr2隐式转换成另一个smart_ptr<X>后,我们需要解决的就是将smartDerivedObjPtr2所拥有的指针传递给smart_ptr<X>并将smartDerivedObjPtr2的内部指针清零(这样就不会在smartDerivedObjPtr2被销毁的时候,因为调用delete real_ptr,而它的新拷贝在离开作用域的时候,一样会再次调用delete real_ptr,而此时real_ptr指向的对象已经被释放,因此这样的行为是未定义的。)
7、因此,定义如下方法即可:
template<class T>
class smart_ptr {
public:
smart_ptr(T* t = 0) {
std::cout << "creating smart_ptr ...smart_ptr(T* t = 0)" << std::endl;
real_ptr = t;
}
template<class U>
smart_ptr(smart_ptr<U>& rhs) : real_ptr(rhs.real_ptr){
std::cout << "creating smart_ptr ...smart_ptr(smart_ptr<U>& rhs)" << std::endl;
rhs.real_ptr = 0;
}
~smart_ptr() {
std::cout << "destoring smart_ptr ..." << std::endl;
delete real_ptr;
}
T* operator ->() const { return real_ptr; }
T& operator *() const { return *real_ptr; }
T* real_ptr;
};
8、但是这里real_ptr按照习惯应该是一个私有成员,而且我们在完成该方法时候,希望能够实现一种所谓的所有权转移,也就是将内部的指针传递给另一个智能指针,而这应该是一个原子过程。因此,我们实现以下方法:
template<class T>
class smart_ptr {
public:
smart_ptr(T* t = 0) {
std::cout << "creating smart_ptr ...smart_ptr(T* t = 0)" << std::endl;
real_ptr = t;
}
template<class U>
smart_ptr(smart_ptr<U>& rhs) : real_ptr(rhs.release()){
std::cout << "creating smart_ptr ...smart_ptr(smart_ptr<U>& rhs)" << std::endl;
}
~smart_ptr() {
std::cout << "destoring smart_ptr ..." << std::endl;
delete real_ptr;
}
T* operator ->() const { return real_ptr; }
T& operator *() const { return *real_ptr; }
// helper
T* release() {
T* tmp = real_ptr;
real_ptr = 0;
return tmp;
}
private:
T* real_ptr;
};