@@ -98,28 +98,84 @@ class XPtr :
9898 return *this ;
9999 }
100100
101+ /* *
102+ * Typesafe accessor for underlying pointer (use checked_get
103+ * if you want an exception thrown if the pointer is NULL)
104+ */
105+ inline T* get () const {
106+ return (T*)(R_ExternalPtrAddr ( Storage::get__ () ));
107+ }
108+
109+ /* *
110+ * Boolean operator wrapper for get() using the "safe bool idiom", see:
111+ * http://www.boost.org/doc/libs/1_57_0/boost/smart_ptr/detail/operator_bool.hpp
112+ */
113+ typedef void (*unspecified_bool_type)();
114+ static void unspecified_bool_true () {}
115+ operator unspecified_bool_type () const
116+ {
117+ return get () == NULL ? 0 : unspecified_bool_true;
118+ }
119+ bool operator !() const
120+ {
121+ return get () == NULL ;
122+ }
123+
124+ /* *
125+ * Access underlying pointer throwing an exception if the ptr is NULL
126+ */
127+ inline T* checked_get () const {
128+ T* ptr = get ();
129+ if (ptr == NULL )
130+ throw ::Rcpp::exception (" external pointer is not valid" ) ;
131+ return ptr;
132+ }
133+
101134 /* *
102135 * Returns a reference to the object wrapped. This allows this
103136 * object to look and feel like a dumb pointer to T
104137 */
105138 T& operator *() const {
106- return *((T*) R_ExternalPtrAddr ( Storage::get__ () )) ;
139+ return *(checked_get ( )) ;
107140 }
108141
109142 /* *
110143 * Returns the dumb pointer. This allows to call the -> operator
111144 * on this as if it was the dumb pointer
112145 */
113146 T* operator ->() const {
114- return (T*)( R_ExternalPtrAddr ( Storage::get__ () )) ;
147+ return checked_get () ;
115148 }
116149
117150 void setDeleteFinalizer () {
118151 R_RegisterCFinalizerEx ( Storage::get__ (), finalizer_wrapper<T,Finalizer> , FALSE ) ;
119152 }
120153
154+ /* *
155+ * Release the external pointer (if any) immediately. This will cause
156+ * the pointer to be deleted and it's storage to be set to NULL.
157+ * After this call the get() method returns NULL and the checked_get()
158+ * method throws an exception.
159+ *
160+ * See the discussion here for the basic logic behind release:
161+ * https://stat.ethz.ch/pipermail/r-help/2007-August/137871.html
162+ */
163+ void release () {
164+
165+ if (get () != NULL )
166+ {
167+ // Call the finalizer -- note that this implies that finalizers
168+ // need to be ready for a NULL external pointer value (our
169+ // default C++ finalizer is since delete NULL is a no-op).
170+ finalizer_wrapper<T,Finalizer>( Storage::get__ () );
171+
172+ // Clear the external pointer
173+ R_ClearExternalPtr ( Storage::get__ () );
174+ }
175+ }
176+
121177 inline operator T*(){
122- return (T*)( R_ExternalPtrAddr ( Storage::get__ () ) ) ;
178+ return checked_get ( ) ;
123179 }
124180
125181 void update (SEXP){}
0 commit comments