MyMSDN

MyMSDN记录开发新知道

智能指针的实现(1)

首先我们面临的挑战是,声明堆中的数据需要我们用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; 
};

posted on 2010-04-04 23:08 volnet 阅读(2367) 评论(1)  编辑 收藏 引用 所属分类: C/C++

评论

# re: 智能指针的实现(1)[未登录] 2010-04-06 11:38 helloworld

没意义,用项目中智能指针只会用smart_ptr,实现了一点意义都没有,重复的轮子  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


特殊功能