1 /***
2 *auto_gcroot.h
3 *
4 *           Copyright (c) Microsoft Corporation. All rights reserved.
5 *
6 *Purpose:     automatic resource management, like std::auto_ptr which can be used
7 *                  to embed a virtual handle into a native type
8 *
9 *           [Public]
10 *
11 ****/
12
13 #pragma once
14
15 #if !defined(_INC_MSCLR_AUTO_GCROOT)
16
17 #ifndef __cplusplus_cli
18 #error ERROR: msclr libraries are not compatible with /clr:oldSyntax
19 #endif
20
21 #include <vcclr.h>
22 #include <msclr\safebool.h>
23 #include <algorithm>
24
25 namespace msclr
26 {
27
28 // Forward Declaration
29 template<typename _element_type>
30 class auto_gcroot;
31
32 namespace _detail
33 {
34
35 // _auto_gcroot_ref is a proxy reference for auto_gcroot copying.
36 // auto_gcroot's copy constructor takes a non-const reference
37 // because it must assume ownership from the source. But this
38 // makes it impossible for auto_gcroot to be returned by value,
39 // because temporary objects cannot be bound to non-const
40 // references. Instead, a conversion to _auto_gcroot_ref is provided,
41 // and an auto_gcroot can be initialized from an _auto_gcroot_ref.
42
43       template<typename _element_type>
44       struct _auto_gcroot_ref
45       {
46              // construct from compatible auto_gcroot
47              _auto_gcroot_ref( auto_gcroot<_element_type> & ref ) 
48                     : m_ref( ref )
49              {
50              }
51
52              // reference to constructor argument
53              auto_gcroot<_element_type> & m_ref;
54
55       };
56
57 } // namespace detail
58
59 // wrap a resource to enforce strict ownership and ensure proper cleanup
60 template<typename _element_type>
61 class auto_gcroot
62 {
63 private:
64       // disallow explicit comparisons to _safe_bool
65       bool operator==( _detail_class::_safe_bool ) const;
66       bool operator!=( _detail_class::_safe_bool ) const;
67       
68 public:
69
70       // Constructors
71       
72       // construct from object pointer
73       auto_gcroot( _element_type _ptr = nullptr ) 
74              : m_ptr( _ptr )
75       {
76       }
77
78       // construct by assuming pointer from _right auto_gcroot
79       auto_gcroot( auto_gcroot<_element_type> & _right ) 
80                     : m_ptr( _right.release() )
81       {
82       }
83
84       // construct by assuming pointer from _right _detail::_auto_gcroot_ref
85       auto_gcroot( _detail::_auto_gcroot_ref<_element_type> _right ) 
86              : m_ptr( _right.m_ref.release() )
87       {
88       }
89
90       template<typename _other_type>
91       auto_gcroot( auto_gcroot<_other_type> & _right ) 
92              : m_ptr( _right.release() )
93       {
94       }
95
96       auto_gcroot<_element_type> & attach(_element_type _right)
97       {
98              reset(_right);
99              return *this;
100       }
101       
102       // assign compatible _right
103       auto_gcroot<_element_type> & attach( 
104              auto_gcroot<_element_type> & _right ) 
105       {
106              reset( _right.release() );
107              return *this;
108       }
109
110       // assign compatible _right.ref
111       auto_gcroot<_element_type> & attach( 
112              _detail::_auto_gcroot_ref<_element_type> & _right ) 
113       {
114              reset( _right.m_ref.release() );
115              return *this;
116       }
117
118       template<typename _other_type>
119       auto_gcroot<_element_type> & attach(
120       auto_gcroot<_other_type> & _right ) 
121       {
122              reset( _right.release() );
123              return *this;
124       }
125
126       auto_gcroot<_element_type> & operator=(_element_type _right)
127       {
Lines 128 ... 137 are skipped.
138       // assign compatible _right.ref
139       auto_gcroot<_element_type> & operator=( 
140              _detail::_auto_gcroot_ref<_element_type> & _right ) 
141       {
142              return attach(_right);
143       }
144
145       template<typename _other_type>
146       auto_gcroot<_element_type> & operator=(
147       auto_gcroot<_other_type> & _right ) 
148       {
149              return attach(_right);
150       }
151
152       _element_type get() const 
153       {
154              return m_ptr;
155       }
156
157       // return pointer to class object (assume pointer)
158       _element_type operator->() const 
159       {
160              return m_ptr;
161       }
162
163       // for use when auto_gcroot appears in a conditional
164       operator _detail_class::_safe_bool() const 
165       {
166              return valid() ? _detail_class::_safe_true : _detail_class::_safe_false;
167       }
168
169       // for use when auto_gcroot appears in a conditional
170       bool operator!() const 
171       {
172              return ! valid();
173       }
174
175       // convert to compatible _detail::_auto_gcroot_ref
176       operator _detail::_auto_gcroot_ref<_element_type>() 
177       {
178              return _detail::_auto_gcroot_ref<_element_type>( *this );
179       }
180
181       template<typename _other_type>
182       operator auto_gcroot<_other_type>() 
183       {
184              return auto_gcroot<_other_type>( *this );
185       }
186
187       template<typename _other_type>
188       operator _detail::_auto_gcroot_ref<_other_type>() 
189       {
190              return _detail::_auto_gcroot_ref<_other_type>( *this );
191       }
192
193       void swap( auto_gcroot<_element_type> & _right ) 
194       {
195              m_ptr.swap( _right.m_ptr );
196       }
197
198       void reset( _element_type _new_ptr = nullptr ) 
199       {
200              if( _element_type(m_ptr) != _new_ptr )
201              {
202                     if( valid() )
203                     {
204                           delete _element_type(m_ptr);
205                     }
206                     m_ptr = _new_ptr;
207              }
208       }
209
210       _element_type release() 
211       {
212              _element_type _tmp_ptr = m_ptr;
213              m_ptr = nullptr;
214              return _tmp_ptr;
215       }
216
217       // destroy the object
218       ~auto_gcroot()
219       {
220              if( valid() )
221              {
222                     delete _element_type(m_ptr);
223              }
224       }
225
226 private:
227
228       bool valid() const 
229       {
230              // see if the managed resource is in the invalid state.
231              return _element_type(m_ptr) != nullptr;
232       }
233
234       // the wrapped object
235       gcroot<_element_type> m_ptr;
236 };
237
238 // swap the contents of two auto_gcroot objects
239 template<typename _element_type>
240 void swap( auto_gcroot<_element_type> & _left, 
241                   auto_gcroot<_element_type> & _right ) 
242 {
243       _left.swap( _right );
244 }
245
246 } // namespace msclr
247
248 #define _INC_MSCLR_AUTO_GCROOT
249
250 #endif // _INC_MSCLR_AUTO_GCROOT
251