1 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
\r
2 // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
\r
3 // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
\r
4 // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
\r
5 // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
\r
6 // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
\r
7 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
\r
8 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
\r
9 // OR OTHER DEALINGS IN THE SOFTWARE.
\r
11 // This software was developed from code available in the public domain
\r
12 // and has no copyright.
\r
15 // About Shared_Ptr:
\r
16 // Shared_Ptr wraps a reference-counted smart pointer around a dynamically
\r
17 // allocated object. Unlike auto_ptr, the Shared_Ptr can be used as a smart
\r
18 // pointer for objects stored in containers like std::vector. Do not use
\r
19 // Shared_Ptr (or shared_ptr or auto_ptr) for dynamically allocated arrays.
\r
20 // See below for advice on how to wrap dynamically allocated arrays in a
\r
23 // The next standard of C++ will also contain a shared_ptr. Some modern
\r
24 // compilers already have a shared_ptr available as std::tr1::shared_ptr. If
\r
25 // your compiler already provides a shared_ptr, or if you have Boost, you
\r
26 // should use that smart pointer instead. This class has been provided for
\r
27 // those users who don't have easy access to an "official" shared_ptr.
\r
28 // Note that this class is "Shared_Ptr", a slightly different name to the
\r
29 // future "shared_ptr" to avoid naming conflicts.
\r
31 // Advantages of Shared_Ptr (or shared_ptr where available):
\r
32 // - Shared_Ptr can be safely copied. This makes then suitable for containers.
\r
33 // - Shared_Ptr automatically calls delete for the wrapped pointer when
\r
34 // its last copy goes out of scope.
\r
35 // - Shared_Ptr simplifies exception safety.
\r
37 // Without smart pointers, it can be quite challenging to ensure that every
\r
38 // dynamically allocated pointer (i.e. use of new) is deleted in the event of
\r
39 // all possible exceptions. In addition to the exceptions we throw ourselves,
\r
40 // "new" itself will throw an exception it it fails, as does the STL (Standard
\r
41 // Template Library which includes vector and string). Without smart pointers
\r
42 // we often need to resort to additional try/catch blocks simply to avoid
\r
43 // memory leaks when exceptions occur.
\r
46 // Shared_Ptr<CWnd> w1(new CWnd);
\r
48 // Shared_Ptr<CWnd> w1 = new CWnd;
\r
50 // typedef Shared_Ptr<CWnd> CWndPtr;
\r
51 // CWndPtr w1 = new CWnd;
\r
53 // typedef Shared_Ptr<CWnd> CWndPtr;
\r
54 // CWndPtr w1(new CWnd);
\r
56 // And with a vector
\r
57 // typedef Shared_Ptr<CWnd> CWndPtr;
\r
58 // std::vector<CWndPtr> MyVector;
\r
59 // MyVector.push_back(new CWnd);
\r
61 // typedef Shared_Ptr<CWnd> CWndPtr;
\r
62 // CWnd* pWnd = new CWnd;
\r
63 // std::vector<CWndPtr> MyVector;
\r
64 // MyVector.push_back(pWnd);
\r
67 // How to handle dynamically allocated arrays:
\r
68 // While we could create a smart pointer for arrays, we don't need to because
\r
69 // std::vector already handles this for us. Consider the following example:
\r
70 // int nLength = ::GetWindowTextLength(m_hWnd);
\r
71 // pTChar = new TCHAR[nLength+1];
\r
72 // memset(pTChar, 0, (nLength+1)*sizeof(TCHAR));
\r
73 // ::GetWindowText(m_hWnd, m_pTChar, nLength+1);
\r
77 // This can be improved by using a vector instead of an array
\r
78 // int nLength = ::GetWindowTextLength(m_hWnd);
\r
79 // std::vector<TCHAR> vTChar( nLength+1, _T('\0') );
\r
80 // TCHAR* pTCharArray = &vTChar.front();
\r
81 // ::GetWindowText(m_hWnd, pTCharArray, nLength+1);
\r
83 // This works because the memory in a vector is always contiguous. Note that
\r
84 // this is NOT always true of std::string.
\r
88 // In my opinion, "naked" pointers for dynamically created objects should be
\r
89 // avoided in modern C++ code. That's to say that calls to "new" should be
\r
90 // wrapped in some sort of smart pointer wherever possible. This eliminates
\r
91 // the possibility of memory leaks (particularly in the event of exceptions).
\r
92 // It also elminiates the need for delete in user's code.
\r
94 #ifndef _WIN32XX_SHARED_PTR_
\r
95 #define _WIN32XX_SHARED_PTR_
\r
100 template <class T1>
\r
104 Shared_Ptr() : m_ptr(NULL), m_count(NULL) { }
\r
105 Shared_Ptr(T1 * p) : m_ptr(p), m_count(NULL)
\r
109 if (m_ptr) m_count = new long(0);
\r
112 // catch the unlikely event of 'new long(0)' throwing an exception
\r
113 catch (const std::bad_alloc&)
\r
119 Shared_Ptr(const Shared_Ptr& rhs) : m_ptr(rhs.m_ptr), m_count(rhs.m_count) { inc_ref(); }
\r
122 if(m_count && 0 == dec_ref())
\r
124 // Note: This code doesn't handle a pointer to an array.
\r
125 // We would need delete[] m_ptr to handle that.
\r
131 T1* get() const { return m_ptr; }
\r
132 long use_count() const { return m_count? *m_count : 0; }
\r
133 bool unique() const { return (m_count && (*m_count == 1)); }
\r
135 void swap(Shared_Ptr& rhs)
\r
137 std::swap(m_ptr, rhs.m_ptr);
\r
138 std::swap(m_count, rhs.m_count);
\r
141 Shared_Ptr& operator=(const Shared_Ptr& rhs)
\r
143 Shared_Ptr tmp(rhs);
\r
148 T1* operator->() const
\r
154 T1& operator*() const
\r
160 bool operator== (const Shared_Ptr& rhs) const
\r
162 return ( *m_ptr == *rhs.m_ptr);
\r
165 bool operator!= (const Shared_Ptr& rhs) const
\r
167 return ( *m_ptr != *rhs.m_ptr);
\r
170 bool operator< (const Shared_Ptr& rhs) const
\r
172 return ( *m_ptr < *rhs.m_ptr );
\r
175 bool operator> (const Shared_Ptr& rhs) const
\r
177 return ( *m_ptr > *rhs.m_ptr );
\r
184 InterlockedIncrement(m_count);
\r
190 return InterlockedDecrement(m_count);
\r
199 #endif // _WIN32XX_SHARED_PTR_
\r