首页 / 技术类 / C++ / 一个轻量级智能指针实现

一个轻量级智能指针实现

2009-09-23 08:07:00

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

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

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

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

 1template <typename T>
 2class QIPtr
 3{
 4public:
 5    QIPtr(T *pData);
 6    ~QIPtr();
 7private:
 8    T *m_pData;
 9    size_t m_cRef; // TBD
10private:
11    void AddRef();
12    void Release();
13};

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

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

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

  1/*******************************************************************************
  2
  3    Copyright (C) Streamlet. All rights reserved.
  4
  5    File Name:   xlQIPtr.h
  6    Author:      Streamlet
  7    Create Time: 2009-03-22
  8    Description: Smart pointer
  9
 10    Version history:
 11        2009-03-22 Created by Streamlet.
 12        2009-03-27 Released first version.(1.0.0.1)
 13
 14
 15*******************************************************************************/
 16
 17#ifndef __XLQIPTR_H_B0788703_ABD1_457D_8FEC_E527581FD9EF_INCLUDED__
 18#define __XLQIPTR_H_B0788703_ABD1_457D_8FEC_E527581FD9EF_INCLUDED__
 19
 20
 21namespace xl
 22{
 23
 24#ifndef NULL
 25#define NULL 0
 26#endif
 27
 28    /// @brief Smart Pointer.
 29    template <typename T>
 30    class QIPtr
 31    {
 32    public:
 33        /**
 34         * @brief Default constructor.
 35         */
 36        QIPtr();
 37
 38        /**
 39         * @brief Constructor. Must give an heap address. Sample use: QIPtr<int> p(new int);.
 40         * @param pData [in] A heap address, usually returned by operator new.
 41         * @remark operator delete must not be called, if using QIPtr.
 42         */
 43        QIPtr(T *pData);
 44
 45        /**
 46         * @brief Copy construction.
 47         * @param that [in] The pointer to be copied.
 48         */
 49        QIPtr(const QIPtr<T> &that);
 50
 51        /**
 52         * @brief Destroyer. Inside this function, the heap address will be released if there is no more references.
 53         */
 54        ~QIPtr();
 55    public:
 56
 57        /**
 58         * @brief Operator *, use it as usual.
 59         * @return return a reference of T-typed object.
 60         */
 61        T &operator*() const;
 62
 63        /**
 64         * @brief Operator ->, use it as usual.
 65         * @return return the address of the object.
 66         */
 67        T *operator->() const;
 68
 69        /**
 70         * @brief Copy operator, use it as usual.
 71         * @param that [in] The pointer to be copied.
 72         * @return Reference of this object
 73         */
 74        QIPtr<T> &operator=(const QIPtr<T> &that);
 75
 76        /**
 77         * @brief Compare operator, use it as usual.
 78         * @param that [in] The pointer to be compared.
 79         * @return Return true if the two points equals, return false otherwise.
 80         */
 81        bool operator==(const QIPtr<T> &that) const;
 82
 83        /**
 84         * @brief Compare operator, use it as usual.
 85         * @param that [in] The pointer to be compared.
 86         * @return Return true if the two points do not equals, return false otherwise.
 87         */
 88        bool operator!=(const QIPtr<T> &that) const;
 89
 90    private:
 91        void AddRef();
 92        void Release();
 93
 94    private:
 95        T *m_pData;
 96        size_t *m_pcRefs;
 97    };
 98
 99    template <typename T>
100    inline void QIPtr<T>::AddRef()
101    {
102        if (this->m_pcRefs == NULL)
103        {
104            this->m_pcRefs = new size_t;
105            *this->m_pcRefs = 0;
106        }
107
108        ++*this->m_pcRefs;
109    }
110
111    template <typename T>
112    inline void QIPtr<T>::Release()
113    {
114        if (this->m_pcRefs == NULL)
115        {
116            return;
117        }
118
119        if (--*this->m_pcRefs > 0)
120        {
121            return;
122        }
123        
124        delete this->m_pcRefs;
125
126        //if (this->m_pData == NULL)
127        //{
128        //    return;
129        //}
130
131        delete this->m_pData;
132    }
133
134
135    template <typename T>
136    inline QIPtr<T>::QIPtr() : m_pData(NULL), m_pcRefs(NULL)
137    {
138    }
139
140    template <typename T>
141    inline QIPtr<T>::QIPtr(T *pData) : m_pData(NULL), m_pcRefs(NULL)
142    {
143        this->m_pData = pData;
144        this->AddRef();
145    }
146
147    template <typename T>
148    inline QIPtr<T>::QIPtr(const QIPtr<T> &that) : m_pData(NULL), m_pcRefs(NULL)
149    {
150        this->m_pData = that.m_pData;
151        this->m_pcRefs = that.m_pcRefs;
152        this->AddRef();
153    }
154
155    template <typename T>
156    inline QIPtr<T>::~QIPtr()
157    {
158        this->Release();
159    }
160
161    template <typename T>
162    inline T &QIPtr<T>::operator*() const
163    {
164        return *this->m_pData;
165    }
166
167    template <typename T>
168    inline T *QIPtr<T>::operator->() const
169    {
170        return this->m_pData;
171    }
172
173    template <typename T>
174    inline QIPtr<T> &QIPtr<T>::operator=(const QIPtr<T> &that)
175    {
176        //if (this == &that)
177        //{
178        //    return *this;
179        //}
180
181        if (this->m_pData == that.m_pData)
182        {
183            return *this;
184        }
185
186        this->Release();
187
188        this->m_pData = that.m_pData;
189        this->m_pcRefs = that.m_pcRefs;
190        this->AddRef();    
191
192        return *this;
193    }
194
195    template <typename T>
196    inline bool QIPtr<T>::operator==(const QIPtr<T> &that) const
197    {
198        return this->m_pData == that.m_pData;
199    }
200
201    template <typename T>
202    inline bool QIPtr<T>::operator!=(const QIPtr<T> &that) const
203    {
204        return this->m_pData != that.m_pData;
205    }
206
207
208} // namespace xl
209
210#endif // #ifndef __XLQIPTR_H_B0788703_ABD1_457D_8FEC_E527581FD9EF_INCLUDED__ 

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


首发:http://www.cppblog.com/Streamlet/archive/2009/09/23/96998.html



NoteIsSite/0.4