開篇語:這是在這里寫的第一篇日志。關于來到這里,主要源于前兩天在這里看到一個牛人(vczh)的文章,花了近兩天斷斷續續拜讀了其文章。他的文章我不是全部能看懂,事實上只看懂了一小部分。還看到一些評論的朋友,也都很牛。因此想到這里來更好的與牛人們交流。如此而已。我原先的博客在 CSDN(http://blog.csdn.net/cnStreamlet/),由于一直以來都比較浮躁,也沒寫什么有用的東西?,F在想想,人家是 05 級,我也是 05 級,人家已經這么牛了,我卻還在金字塔的底層徘徊。人生短短幾個秋,年輕的時候是個學習的黃金時間,浪費了豈不太可惜?總之呢,不管能不能靜下心來,現在開始努力靜下心來,多學點技術,即便成不了牛人,至少可以多些茶余飯后的談資。
==========華麗的分割線==========
好了,言歸正傳。今年 3 月份,也就是上班的第一個月,那時候我還算比較淡定的,經常研究些玩意兒。那時寫了個很輕量級的智能指針。現在不妨拿出來復習一下,如果有朋友路過,歡迎指教。
我所理解的“智能指針”,就是達到 new 了之后不用 delete 的效果。利用棧變量在作用域結束后會自動釋放(對象自動析構)的機制,可以達到這個效果。設想有一個類,它以一個現有指針為參數進行構造,這個析夠的時候去 delete 這個指針,就可以了。然后問題來了,在這種情形下,這個類本身充當了指針這個角色,那么難免要被復制來復制去,這個類中的原始指針也要被復制,那么,顯然析構函數里不能簡單地 delete 了。這時候,比較流行的做法之一是使用引用計數,當某個對象被復制一次,計數加 1;被析構一次,計數減 1。當且僅當計數為 0 的時候才執行 delete?,F在,這個類的雛形大概是:
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
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(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__
寫了這么粗淺的文字,希望大家不要笑話。請多指教。
posted on 2009-09-23 08:07
溪流 閱讀(572)
評論(4) 編輯 收藏 引用 所屬分類:
C++