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
(当然,拷贝构造函数以及赋值函数现在还没实现,但这不妨碍我们想象他们的功能),p1
和 p2
里的 m_pData
共享一块内存,而 m_cRef
却是独立的,也就是说,p1
的 Release()
操作将无法影响到 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