1 // Baruch Even baruch@ev-en.org 2001-02-20
2 // This version is a modified version for use in LyX
3 // The modifications are done in order to use it where exceptions are disabled
4 // Currently it has no "no memory" checks in place, asserts are probably the
6 // all changed are #ifded'ed by LYX_NO_EXCEPTIONS
7 #define LYX_NO_EXCEPTIONS
9 // Boost smart_ptr.hpp header file -----------------------------------------//
11 // (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. Permission to copy,
12 // use, modify, sell and distribute this software is granted provided this
13 // copyright notice appears in all copies. This software is provided "as is"
14 // without express or implied warranty, and with no claim as to its
15 // suitability for any purpose.
17 // See http://www.boost.org for most recent version including documentation.
20 // 6 Jul 01 Reorder shared_ptr code so VC++ 6 member templates work, allowing
21 // polymorphic pointers to now work with that compiler (Gary Powell)
22 // 21 May 01 Require complete type where incomplete type is unsafe.
23 // (suggested by Vladimir Prus)
24 // 21 May 01 operator= fails if operand transitively owned by *this, as in a
25 // linked list (report by Ken Johnson, fix by Beman Dawes)
26 // 21 Jan 01 Suppress some useless warnings with MSVC (David Abrahams)
27 // 19 Oct 00 Make shared_ptr ctor from auto_ptr explicit. (Robert Vugts)
28 // 24 Jul 00 Change throw() to // never throws. See lib guidelines
29 // Exception-specification rationale. (Beman Dawes)
30 // 22 Jun 00 Remove #if continuations to fix GCC 2.95.2 problem (Beman Dawes)
31 // 1 Feb 00 Additional shared_ptr BOOST_NO_MEMBER_TEMPLATES workarounds
33 // 31 Dec 99 Condition tightened for no member template friend workaround
35 // 30 Dec 99 Moved BOOST_NMEMBER_TEMPLATES compatibility code to config.hpp
37 // 30 Nov 99 added operator ==, operator !=, and std::swap and std::less
38 // specializations for shared types (Darin Adler)
39 // 11 Oct 99 replaced op[](int) with op[](std::size_t) (Ed Brey, Valentin
40 // Bonnard), added shared_ptr workaround for no member template
41 // friends (Matthew Langston)
42 // 25 Sep 99 added shared_ptr::swap and shared_array::swap (Luis Coelho).
43 // 20 Jul 99 changed name to smart_ptr.hpp, #include <boost/config.hpp>,
44 // #include <boost/utility.hpp> and use boost::noncopyable
45 // 17 May 99 remove scoped_array and shared_array operator*() as
46 // unnecessary (Beman Dawes)
47 // 14 May 99 reorder code so no effects when bad_alloc thrown (Abrahams/Dawes)
48 // 13 May 99 remove certain throw() specifiers to avoid generated try/catch
49 // code cost (Beman Dawes)
50 // 11 May 99 get() added, conversion to T* placed in macro guard (Valentin
51 // Bonnard, Dave Abrahams, and others argued for elimination
52 // of the automatic conversion)
53 // 28 Apr 99 #include <memory> fix (Valentin Bonnard)
54 // 28 Apr 99 rename transfer() to share() for clarity (Dave Abrahams)
55 // 28 Apr 99 remove unsafe shared_array template conversions(Valentin Bonnard)
56 // 28 Apr 99 p(r) changed to p(r.px) for clarity (Dave Abrahams)
57 // 21 Apr 99 reset() self assignment fix (Valentin Bonnard)
58 // 21 Apr 99 dispose() provided to improve clarity (Valentin Bonnard)
59 // 27 Apr 99 leak when new throws fixes (Dave Abrahams)
60 // 21 Oct 98 initial Version (Greg Colvin/Beman Dawes)
62 #ifndef BOOST_SMART_PTR_HPP
63 #define BOOST_SMART_PTR_HPP
65 #include <boost/config.hpp> // for broken compiler workarounds
66 #include <cstddef> // for std::size_t
67 #include <memory> // for std::auto_ptr
68 #include <algorithm> // for std::swap
69 #include <boost/utility.hpp> // for boost::noncopyable, checked_delete, checked_array_delete
70 #include <functional> // for std::less
71 #include <boost/static_assert.hpp> // for BOOST_STATIC_ASSERT
73 #ifdef LYX_NO_EXCEPTIONS
77 #ifdef BOOST_MSVC // moved here to work around VC++ compiler crash
78 # pragma warning(push)
79 # pragma warning(disable:4284) // return type for 'identifier::operator->' is not a UDT or reference to a UDT. Will produce errors if applied using infix notation
84 // scoped_ptr --------------------------------------------------------------//
86 // scoped_ptr mimics a built-in pointer except that it guarantees deletion
87 // of the object pointed to, either on destruction of the scoped_ptr or via
88 // an explicit reset(). scoped_ptr is a simple solution for simple needs;
89 // see shared_ptr (below) or std::auto_ptr if your needs are more complex.
91 template<typename T> class scoped_ptr : noncopyable {
96 typedef T element_type;
98 explicit scoped_ptr( T* p=0 ) : ptr(p) {} // never throws
99 ~scoped_ptr() { checked_delete(ptr); }
100 void reset( T* p=0 ) { if ( ptr != p ) { checked_delete(ptr); ptr = p; } }
101 T& operator*() const { return *ptr; } // never throws
102 T* operator->() const { return ptr; } // never throws
103 T* get() const { return ptr; } // never throws
104 #ifdef BOOST_SMART_PTR_CONVERSION
105 // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk!
106 operator T*() const { return ptr; } // never throws
110 // scoped_array ------------------------------------------------------------//
112 // scoped_array extends scoped_ptr to arrays. Deletion of the array pointed to
113 // is guaranteed, either on destruction of the scoped_array or via an explicit
114 // reset(). See shared_array or std::vector if your needs are more complex.
116 template<typename T> class scoped_array : noncopyable {
121 typedef T element_type;
123 explicit scoped_array( T* p=0 ) : ptr(p) {} // never throws
124 ~scoped_array() { checked_array_delete(ptr); }
126 void reset( T* p=0 ) { if ( ptr != p )
127 {checked_array_delete(ptr); ptr=p;} }
129 T* get() const { return ptr; } // never throws
130 #ifdef BOOST_SMART_PTR_CONVERSION
131 // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk!
132 operator T*() const { return ptr; } // never throws
134 T& operator[](std::size_t i) const { return ptr[i]; } // never throws
138 // shared_ptr --------------------------------------------------------------//
140 // An enhanced relative of scoped_ptr with reference counted copy semantics.
141 // The object pointed to is deleted when the last shared_ptr pointing to it
142 // is destroyed or reset.
144 template<typename T> class shared_ptr {
146 typedef T element_type;
148 explicit shared_ptr(T* p =0) : px(p) {
149 #ifndef LYX_NO_EXCEPTIONS
150 try { pn = new long(1); } // fix: prevent leak if new throws
151 catch (...) { checked_delete(p); throw; }
158 ~shared_ptr() { dispose(); }
160 #if !defined( BOOST_NO_MEMBER_TEMPLATES ) || defined (BOOST_MSVC6_MEMBER_TEMPLATES)
162 shared_ptr(const shared_ptr<Y>& r) : px(r.px) { // never throws
165 #ifndef BOOST_NO_AUTO_PTR
167 explicit shared_ptr(std::auto_ptr<Y>& r) {
168 pn = new long(1); // may throw
169 px = r.release(); // fix: moved here to stop leak if new throws
174 shared_ptr& operator=(const shared_ptr<Y>& r) {
179 #ifndef BOOST_NO_AUTO_PTR
181 shared_ptr& operator=(std::auto_ptr<Y>& r) {
182 // code choice driven by guarantee of "no effect if new throws"
183 if (*pn == 1) { checked_delete(px); }
184 else { // allocate new reference counter
185 long * tmp = new long(1); // may throw
186 --*pn; // only decrement once danger of new throwing is past
188 } // allocate new reference counter
189 px = r.release(); // fix: moved here so doesn't leak if new throws
194 #ifndef BOOST_NO_AUTO_PTR
195 explicit shared_ptr(std::auto_ptr<T>& r) {
196 pn = new long(1); // may throw
197 px = r.release(); // fix: moved here to stop leak if new throws
200 shared_ptr& operator=(std::auto_ptr<T>& r) {
201 // code choice driven by guarantee of "no effect if new throws"
202 if (*pn == 1) { checked_delete(px); }
203 else { // allocate new reference counter
204 long * tmp = new long(1); // may throw
205 --*pn; // only decrement once danger of new throwing is past
207 } // allocate new reference counter
208 px = r.release(); // fix: moved here so doesn't leak if new throws
214 // The assignment operator and the copy constructor must come after
215 // the templated versions for MSVC6 to work. (Gary Powell)
216 shared_ptr(const shared_ptr& r) : px(r.px) { ++*(pn = r.pn); } // never throws
218 shared_ptr& operator=(const shared_ptr& r) {
224 if ( px == p ) return; // fix: self-assignment safe
225 if (--*pn == 0) { checked_delete(px); }
226 else { // allocate new reference counter
227 #ifndef LYX_NO_EXCEPTIONS
228 try { pn = new long; } // fix: prevent leak if new throws
230 ++*pn; // undo effect of --*pn above to meet effects guarantee
238 } // allocate new reference counter
243 T& operator*() const { return *px; } // never throws
244 T* operator->() const { return px; } // never throws
245 T* get() const { return px; } // never throws
246 #ifdef BOOST_SMART_PTR_CONVERSION
247 // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk!
248 operator T*() const { return px; } // never throws
251 long use_count() const { return *pn; } // never throws
252 bool unique() const { return *pn == 1; } // never throws
254 void swap(shared_ptr<T>& other) // never throws
255 { std::swap(px,other.px); std::swap(pn,other.pn); }
257 // Tasteless as this may seem, making all members public allows member templates
258 // to work in the absence of member template friends. (Matthew Langston)
259 // Don't split this line into two; that causes problems for some GCC 2.95.2 builds
260 #if ( defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(BOOST_MSVC6_MEMBER_TEMPLATES) ) || !defined( BOOST_NO_MEMBER_TEMPLATE_FRIENDS )
264 T* px; // contained pointer
265 long* pn; // ptr to reference counter
267 // Don't split this line into two; that causes problems for some GCC 2.95.2 builds
268 #if !defined( BOOST_NO_MEMBER_TEMPLATES ) && !defined( BOOST_NO_MEMBER_TEMPLATE_FRIENDS )
269 template<typename Y> friend class shared_ptr;
272 void dispose() { if (--*pn == 0) { checked_delete(px); delete pn; } }
274 void share(T* rpx, long* rpn) {
275 if (pn != rpn) { // Q: why not px != rpx? A: fails when both == 0
276 ++*rpn; // done before dispose() in case rpn transitively
277 // dependent on *this (bug reported by Ken Johnson)
285 template<typename T, typename U>
286 inline bool operator==(const shared_ptr<T>& a, const shared_ptr<U>& b)
287 { return a.get() == b.get(); }
289 template<typename T, typename U>
290 inline bool operator!=(const shared_ptr<T>& a, const shared_ptr<U>& b)
291 { return a.get() != b.get(); }
293 // shared_array ------------------------------------------------------------//
295 // shared_array extends shared_ptr to arrays.
296 // The array pointed to is deleted when the last shared_array pointing to it
297 // is destroyed or reset.
299 template<typename T> class shared_array {
301 typedef T element_type;
303 explicit shared_array(T* p =0) : px(p) {
304 #ifndef LYX_NO_EXCEPTIONS
305 try { pn = new long(1); } // fix: prevent leak if new throws
306 catch (...) { checked_array_delete(p); throw; }
313 shared_array(const shared_array& r) : px(r.px) // never throws
316 ~shared_array() { dispose(); }
318 shared_array& operator=(const shared_array& r) {
319 if (pn != r.pn) { // Q: why not px != r.px? A: fails when both px == 0
320 ++*r.pn; // done before dispose() in case r.pn transitively
321 // dependent on *this (bug reported by Ken Johnson)
330 if ( px == p ) return; // fix: self-assignment safe
331 if (--*pn == 0) { checked_array_delete(px); }
332 else { // allocate new reference counter
333 #ifndef LYX_NO_EXCEPTIONS
334 try { pn = new long; } // fix: prevent leak if new throws
336 ++*pn; // undo effect of --*pn above to meet effects guarantee
337 checked_array_delete(p);
344 } // allocate new reference counter
349 T* get() const { return px; } // never throws
350 #ifdef BOOST_SMART_PTR_CONVERSION
351 // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk!
352 operator T*() const { return px; } // never throws
354 T& operator[](std::size_t i) const { return px[i]; } // never throws
357 long use_count() const { return *pn; } // never throws
358 bool unique() const { return *pn == 1; } // never throws
360 void swap(shared_array<T>& other) // never throws
361 { std::swap(px,other.px); std::swap(pn,other.pn); }
365 T* px; // contained pointer
366 long* pn; // ptr to reference counter
368 void dispose() { if (--*pn == 0) { checked_array_delete(px); delete pn; } }
373 inline bool operator==(const shared_array<T>& a, const shared_array<T>& b)
374 { return a.get() == b.get(); }
377 inline bool operator!=(const shared_array<T>& a, const shared_array<T>& b)
378 { return a.get() != b.get(); }
382 // specializations for things in namespace std -----------------------------//
384 #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
388 // Specialize std::swap to use the fast, non-throwing swap that's provided
389 // as a member function instead of using the default algorithm which creates
390 // a temporary and uses assignment.
393 inline void swap(boost::shared_ptr<T>& a, boost::shared_ptr<T>& b)
397 inline void swap(boost::shared_array<T>& a, boost::shared_array<T>& b)
400 // Specialize std::less so we can use shared pointers and arrays as keys in
401 // associative collections.
403 // It's still a controversial question whether this is better than supplying
404 // a full range of comparison operators (<, >, <=, >=).
407 struct less< boost::shared_ptr<T> >
408 : binary_function<boost::shared_ptr<T>, boost::shared_ptr<T>, bool>
410 bool operator()(const boost::shared_ptr<T>& a,
411 const boost::shared_ptr<T>& b) const
412 { return less<T*>()(a.get(),b.get()); }
416 struct less< boost::shared_array<T> >
417 : binary_function<boost::shared_array<T>, boost::shared_array<T>, bool>
419 bool operator()(const boost::shared_array<T>& a,
420 const boost::shared_array<T>& b) const
421 { return less<T*>()(a.get(),b.get()); }
426 #endif // ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
429 # pragma warning(pop)
432 #endif // BOOST_SMART_PTR_HPP