随笔-90  评论-947  文章-0  trackbacks-0
开篇语:这是在这里写的第一篇日志。关于来到这里,主要源于前两天在这里看到一个牛人(vczh)的文章,花了近两天断断续续拜读了其文章。他的文章我不是全部能看懂,事实上只看懂了一小部分。还看到一些评论的朋友,也都很牛。因此想到这里来更好的与牛人们交流。如此而已。我原先的博客在 CSDN(http://blog.csdn.net/cnStreamlet/),由于一直以来都比较浮躁,也没写什么有用的东西。现在想想,人家是 05 级,我也是 05 级,人家已经这么牛了,我却还在金字塔的底层徘徊。人生短短几个秋,年轻的时候是个学习的黄金时间,浪费了岂不太可惜?总之呢,不管能不能静下心来,现在开始努力静下心来,多学点技术,即便成不了牛人,至少可以多些茶余饭后的谈资。

==========华丽的分割线==========

好了,言归正传。今年 3 月份,也就是上班的第一个月,那时候我还算比较淡定的,经常研究些玩意儿。那时写了个很轻量级的智能指针。现在不妨拿出来复习一下,如果有朋友路过,欢迎指教。

我所理解的“智能指针”,就是达到 new 了之后不用 delete 的效果。利用栈变量在作用域结束后会自动释放(对象自动析构)的机制,可以达到这个效果。设想有一个类,它以一个现有指针为参数进行构造,这个析够的时候去 delete 这个指针,就可以了。然后问题来了,在这种情形下,这个类本身充当了指针这个角色,那么难免要被复制来复制去,这个类中的原始指针也要被复制,那么,显然析构函数里不能简单地 delete 了。这时候,比较流行的做法之一是使用引用计数,当某个对象被复制一次,计数加 1;被析构一次,计数减 1。当且仅当计数为 0 的时候才执行 delete。现在,这个类的雏形大概是:

template <typename T>
class QIPtr
{
public:
    
QIPtr(*pData);
    ~
QIPtr();
private:
    
*m_pData;
    
size_t m_cRef// TBD
private:
    
void AddRef();
    
void Release();
};


我现在很随意地放了一个 size_t m_cRef,但是细想一下这样是不行的。假设有 QIPtr p1(new int);,又有 QIPtr p2 = p1(当然,拷贝构造函数以及赋值函数现在还没实现,但这不妨碍我们想象他们的功能),p1 和 p2 里的 m_pData 共享一块内存,而 m_cRef 却是独立的,也就是说,p1 的 Release() 操作将无法影响到 p2。为了解决这个问题,可以将引用计数也定为指针 size_t *m_pcRef,当一个对象被使用原始指针构造的时候,同时给 m_pcRef new 一个出来;如果是 QIPtr 对象之间拷贝拷贝去,则将他们的 m_pcRef 也同步拷贝,并且让 *m_pcRef 自增即可。

当时我就做到这种程度(现在还是)。不过留有一个问题,这个智能指针不是线程安全的,原因在于 AddRef() 和 Release() 期间没有加锁。

代码比较短,就 200 行左右,如下:

/*******************************************************************************

    Copyright (C) Streamlet. All rights reserved.

    File Name:   xlQIPtr.h
    Author:      Streamlet
    Create Time: 2009-03-22
    Description: Smart pointer

    Version history:
        2009-03-22 Created by Streamlet.
        2009-03-27 Released first version.(1.0.0.1)


*******************************************************************************/

#ifndef __XLQIPTR_H_B0788703_ABD1_457D_8FEC_E527581FD9EF_INCLUDED__
#define __XLQIPTR_H_B0788703_ABD1_457D_8FEC_E527581FD9EF_INCLUDED__


namespace xl
{

#ifndef NULL
#define NULL 0
#endif

    
/// @brief Smart Pointer.
    
template <typename T>
    
class QIPtr
    
{
    
public:
        
/**
         * @brief Default constructor.
         */
        
QIPtr();

        
/**
         * @brief Constructor. Must give an heap address. Sample use: QIPtr<int> p(new int);.
         * @param pData [in] A heap address, usually returned by operator new.
         * @remark operator delete must not be called, if using QIPtr.
         */
        
QIPtr(*pData);

        
/**
         * @brief Copy construction.
         * @param that [in] The pointer to be copied.
         */
        
QIPtr(const QIPtr<T> &that);

        
/**
         * @brief Destroyer. Inside this function, the heap address will be released if there is no more references.
         */
        
~QIPtr();
    
public:

        
/**
         * @brief Operator *, use it as usual.
         * @return return a reference of T-typed object.
         */
        
&operator*() const;

        
/**
         * @brief Operator ->, use it as usual.
         * @return return the address of the object.
         */
        
*operator->() const;

        
/**
         * @brief Copy operator, use it as usual.
         * @param that [in] The pointer to be copied.
         * @return Reference of this object
         */
        
QIPtr<T> &operator=(const QIPtr<T> &that);

        
/**
         * @brief Compare operator, use it as usual.
         * @param that [in] The pointer to be compared.
         * @return Return true if the two points equals, return false otherwise.
         */
        
bool operator==(const QIPtr<T> &thatconst;

        
/**
         * @brief Compare operator, use it as usual.
         * @param that [in] The pointer to be compared.
         * @return Return true if the two points do not equals, return false otherwise.
         */
        
bool operator!=(const QIPtr<T> &thatconst;

    
private:
        
void AddRef();
        
void Release();

    
private:
        
*m_pData;
        
size_t *m_pcRefs;
    };

    
template <typename T>
    
inline void QIPtr<T>::AddRef()
    {
        
if (this->m_pcRefs == NULL)
        {
            
this->m_pcRefs new size_t;
            *
this->m_pcRefs 0;
        }

        ++*
this->m_pcRefs;
    }

    
template <typename T>
    
inline void QIPtr<T>::Release()
    {
        
if (this->m_pcRefs == NULL)
        {
            
return;
        }

        
if (--*this->m_pcRefs 0)
        {
            
return;
        }
        
        
delete this->m_pcRefs;

        
//if (this->m_pData == NULL)
        //{
        //    return;
        //}

        
delete this->m_pData;
    }


    
template <typename T>
    
inline QIPtr<T>::QIPtr() : m_pData(NULL), m_pcRefs(NULL)
    {
    }

    
template <typename T>
    
inline QIPtr<T>::QIPtr(*pData) : m_pData(NULL), m_pcRefs(NULL)
    {
        
this->m_pData pData;
        
this->AddRef();
    }

    
template <typename T>
    
inline QIPtr<T>::QIPtr(const QIPtr<T> &that) : m_pData(NULL), m_pcRefs(NULL)
    {
        
this->m_pData that.m_pData;
        
this->m_pcRefs that.m_pcRefs;
        
this->AddRef();
    }

    
template <typename T>
    
inline QIPtr<T>::~QIPtr()
    {
        
this->Release();
    }

    
template <typename T>
    
inline &QIPtr<T>::operator*() const
    
{
        
return *this->m_pData;
    }

    
template <typename T>
    
inline *QIPtr<T>::operator->() const
    
{
        
return this->m_pData;
    }

    
template <typename T>
    
inline QIPtr<T> &QIPtr<T>::operator=(const QIPtr<T> &that)
    {
        
//if (this == &that)
        //{
        //    return *this;
        //}

        
if (this->m_pData == that.m_pData)
        {
            
return *this;
        }

        
this->Release();

        
this->m_pData that.m_pData;
        
this->m_pcRefs that.m_pcRefs;
        
this->AddRef();    

        
return *this;
    }

    
template <typename T>
    
inline bool QIPtr<T>::operator==(const QIPtr<T> &thatconst
    
{
        
return this->m_pData == that.m_pData;
    }

    
template <typename T>
    
inline bool QIPtr<T>::operator!=(const QIPtr<T> &thatconst
    
{
        
return this->m_pData != that.m_pData;
    }


// namespace xl

#endif // #ifndef __XLQIPTR_H_B0788703_ABD1_457D_8FEC_E527581FD9EF_INCLUDED__


写了这么粗浅的文字,希望大家不要笑话。请多指教。

posted on 2009-09-23 08:07 溪流 阅读(565) 评论(4)  编辑 收藏 引用 所属分类: C++

评论:
# re: 一个轻量级智能指针实现[未登录] 2009-09-23 21:24 | cppexplore
智能指针常用的就是线程间传递指针类型数据的时候,导致两个线程不能确定该指针释放的时间点,所以基本上不加锁的智能指针用处不大。  回复  更多评论
  
# re: 一个轻量级智能指针实现 2009-09-23 21:45 | 溪流
@cppexplore

呵呵,所以现在的用途也仅仅在于虽然能确定在什么时候释放但是想偷懒的时候了。请教一下,加锁的话,是否只能调用操作系统的 API(这意味着这个智能指针实现已经平台相关了)?C++ 语言本身有没有提供类似机制呢?  回复  更多评论
  
# re: 一个轻量级智能指针实现[未登录] 2009-09-23 22:25 | cppexplore
语言层面没有这种机制。
可以用boost 或者自己封装一层屏蔽os差异  回复  更多评论
  
# re: 一个轻量级智能指针实现 2009-09-23 23:07 | 溪流
@cppexplore

了解了,谢谢。不过我想我不能直接使用 boost,最多参考一下它的做法。我准备慢慢积累一个自己的库,不依赖于现有任何库。可能要等对 OS 相关的东西写好了再回过头来审视了。  回复  更多评论
  

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