一个轻量级智能指针实现
开篇语:这是在这里写的第一篇日志。关于来到这里,主要源于前两天在这里看到一个牛人(vczh)的文章,花了近两天断断续续拜读了其文章。他的文章我不是全部能看懂,事实上只看懂了一小部分。还看到一些评论的朋友,也都很牛。因此想到这里来更好的与牛人们交流。如此而已。我原先的博客在 CSDN(http://blog.csdn.net/cnStreamlet/),由于一直以来都比较浮躁,也没写什么有用的东西。现在想想,人家是 05 级,我也是 05 级,人家已经这么牛了,我却还在金字塔的底层徘徊。人生短短几个秋,年轻的时候是个学习的黄金时间,浪费了岂不太可惜?总之呢,不管能不能静下心来,现在开始努力静下心来,多学点技术,即便成不了牛人,至少可以多些茶余饭后的谈资。
==========华丽的分割线==========
好了,言归正传。今年 3 月份,也就是上班的第一个月,那时候我还算比较淡定的,经常研究些玩意儿。那时写了个很轻量级的智能指针。现在不妨拿出来复习一下,如果有朋友路过,欢迎指教。
我所理解的“智能指针”,就是达到 new 了之后不用 delete 的效果。利用栈变量在作用域结束后会自动释放(对象自动析构)的机制,可以达到这个效果。设想有一个类,它以一个现有指针为参数进行构造,这个析够的时候去 delete 这个指针,就可以了。然后问题来了,在这种情形下,这个类本身充当了指针这个角色,那么难免要被复制来复制去,这个类中的原始指针也要被复制,那么,显然析构函数里不能简单地 delete 了。这时候,比较流行的做法之一是使用引用计数,当某个对象被复制一次,计数加 1;被析构一次,计数减 1。当且仅当计数为 0 的时候才执行 delete。现在,这个类的雏形大概是:
我现在很随意地放了一个 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 行左右,如下:
写了这么粗浅的文字,希望大家不要笑话。请多指教。
==========华丽的分割线==========
好了,言归正传。今年 3 月份,也就是上班的第一个月,那时候我还算比较淡定的,经常研究些玩意儿。那时写了个很轻量级的智能指针。现在不妨拿出来复习一下,如果有朋友路过,欢迎指教。
我所理解的“智能指针”,就是达到 new 了之后不用 delete 的效果。利用栈变量在作用域结束后会自动释放(对象自动析构)的机制,可以达到这个效果。设想有一个类,它以一个现有指针为参数进行构造,这个析够的时候去 delete 这个指针,就可以了。然后问题来了,在这种情形下,这个类本身充当了指针这个角色,那么难免要被复制来复制去,这个类中的原始指针也要被复制,那么,显然析构函数里不能简单地 delete 了。这时候,比较流行的做法之一是使用引用计数,当某个对象被复制一次,计数加 1;被析构一次,计数减 1。当且仅当计数为 0 的时候才执行 delete。现在,这个类的雏形大概是:
template <typename T>
class QIPtr
{
public:
QIPtr(T *pData);
~QIPtr();
private:
T *m_pData;
size_t m_cRef; // TBD
private:
void AddRef();
void Release();
};
我现在很随意地放了一个 size_t m_cRef,但是细想一下这样是不行的。假设有 QIPtr
当时我就做到这种程度(现在还是)。不过留有一个问题,这个智能指针不是线程安全的,原因在于 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(T *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.
*/
T &operator*() const;
/**
* @brief Operator ->, use it as usual.
* @return return the address of the object.
*/
T *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> &that) const;
/**
* @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> &that) const;
private:
void AddRef();
void Release();
private:
T *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(T *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 T &QIPtr<T>::operator*() const
{
return *this->m_pData;
}
template <typename T>
inline T *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> &that) const
{
return this->m_pData == that.m_pData;
}
template <typename T>
inline bool QIPtr<T>::operator!=(const QIPtr<T> &that) const
{
return this->m_pData != that.m_pData;
}
} // namespace xl
#endif // #ifndef __XLQIPTR_H_B0788703_ABD1_457D_8FEC_E527581FD9EF_INCLUDED__
写了这么粗浅的文字,希望大家不要笑话。请多指教。