@@ -56,36 +56,43 @@ High-level aspects:
56
56
namespace pybindit {
57
57
namespace memory {
58
58
59
- template <typename T>
60
- struct guarded_builtin_delete {
61
- std::shared_ptr<bool > flag_ptr;
62
- explicit guarded_builtin_delete (std::shared_ptr<bool > armed_flag_ptr)
63
- : flag_ptr{armed_flag_ptr} {}
64
- template <typename T_ = T,
65
- typename std::enable_if<std::is_destructible<T_>::value, int >::type = 0 >
66
- void operator ()(T *raw_ptr) {
67
- if (*flag_ptr)
68
- delete raw_ptr;
69
- }
70
- template <typename T_ = T,
71
- typename std::enable_if<!std::is_destructible<T_>::value, int >::type = 0 >
72
- void operator ()(T *) {
73
- // This noop operator is needed to avoid a compilation error (for `delete raw_ptr;`), but
74
- // throwing an exception from here could std::terminate the process. Therefore the runtime
75
- // check for lifetime-management correctness is implemented elsewhere (in
76
- // ensure_pointee_is_destructible()).
59
+ struct guarded_delete {
60
+ void (*del_ptr)(void *);
61
+ bool armed_flag;
62
+ guarded_delete (void (*del_ptr)(void *), bool armed_flag)
63
+ : del_ptr{del_ptr}, armed_flag{armed_flag} {}
64
+ void operator ()(void *raw_ptr) const {
65
+ if (armed_flag)
66
+ (*del_ptr)(raw_ptr);
77
67
}
78
68
};
79
69
70
+ template <typename T, typename std::enable_if<std::is_destructible<T>::value, int >::type = 0 >
71
+ inline void builtin_delete_if_destructible (void *raw_ptr) {
72
+ delete (T *) raw_ptr;
73
+ }
74
+
75
+ template <typename T, typename std::enable_if<!std::is_destructible<T>::value, int >::type = 0 >
76
+ inline void builtin_delete_if_destructible (void *) {
77
+ // This noop operator is needed to avoid a compilation error (for `delete raw_ptr;`), but
78
+ // throwing an exception from a destructor will std::terminate the process. Therefore the
79
+ // runtime check for lifetime-management correctness is implemented elsewhere (in
80
+ // ensure_pointee_is_destructible()).
81
+ }
82
+
83
+ template <typename T>
84
+ guarded_delete make_guarded_builtin_delete (bool armed_flag) {
85
+ return guarded_delete (builtin_delete_if_destructible<T>, armed_flag);
86
+ }
87
+
80
88
template <typename T, typename D>
81
- struct guarded_custom_deleter {
82
- std::shared_ptr<bool > flag_ptr;
83
- explicit guarded_custom_deleter (std::shared_ptr<bool > armed_flag_ptr)
84
- : flag_ptr{armed_flag_ptr} {}
85
- void operator ()(T *raw_ptr) {
86
- if (*flag_ptr)
87
- D ()(raw_ptr);
88
- }
89
+ inline void custom_delete (void *raw_ptr) {
90
+ D ()((T *) raw_ptr);
91
+ }
92
+
93
+ template <typename T, typename D>
94
+ guarded_delete make_guarded_custom_deleter (bool armed_flag) {
95
+ return guarded_delete (custom_delete<T, D>, armed_flag);
89
96
};
90
97
91
98
template <typename T>
@@ -96,7 +103,6 @@ inline bool is_std_default_delete(const std::type_info &rtti_deleter) {
96
103
97
104
struct smart_holder {
98
105
const std::type_info *rtti_uqp_del = nullptr ;
99
- std::shared_ptr<bool > vptr_deleter_armed_flag_ptr;
100
106
std::shared_ptr<void > vptr;
101
107
bool vptr_is_using_noop_deleter : 1 ;
102
108
bool vptr_is_using_builtin_delete : 1 ;
@@ -108,20 +114,14 @@ struct smart_holder {
108
114
// Design choice: smart_holder is movable but not copyable.
109
115
smart_holder (smart_holder &&) = default ;
110
116
smart_holder (const smart_holder &) = delete ;
111
- smart_holder &operator =(smart_holder &&) = default ;
117
+ smart_holder &operator =(smart_holder &&) = delete ;
112
118
smart_holder &operator =(const smart_holder &) = delete ;
113
119
114
120
smart_holder ()
115
121
: vptr_is_using_noop_deleter{false }, vptr_is_using_builtin_delete{false },
116
122
vptr_is_external_shared_ptr{false }, is_populated{false }, is_disowned{false },
117
123
pointee_depends_on_holder_owner{false } {}
118
124
119
- explicit smart_holder (bool vptr_deleter_armed_flag)
120
- : vptr_deleter_armed_flag_ptr{new bool {vptr_deleter_armed_flag}},
121
- vptr_is_using_noop_deleter{false }, vptr_is_using_builtin_delete{false },
122
- vptr_is_external_shared_ptr{false }, is_populated{false }, is_disowned{false },
123
- pointee_depends_on_holder_owner{false } {}
124
-
125
125
bool has_pointee () const { return vptr.get () != nullptr ; }
126
126
127
127
template <typename T>
@@ -194,10 +194,20 @@ struct smart_holder {
194
194
}
195
195
}
196
196
197
+ void reset_vptr_deleter_armed_flag (bool armed_flag) {
198
+ // The const_cast is only for certain compilers (Ubuntu 20 GCC 6.3.0 being one).
199
+ auto vptr_del_ptr = const_cast <guarded_delete *>(std::get_deleter<guarded_delete>(vptr));
200
+ if (vptr_del_ptr == nullptr ) {
201
+ throw std::runtime_error (
202
+ " smart_holder::reset_vptr_deleter_armed_flag() called in an invalid context." );
203
+ }
204
+ vptr_del_ptr->armed_flag = armed_flag;
205
+ }
206
+
197
207
template <typename T>
198
208
static smart_holder from_raw_ptr_unowned (T *raw_ptr) {
199
- smart_holder hld ( false ) ;
200
- hld.vptr .reset (raw_ptr, guarded_builtin_delete<T>(hld. vptr_deleter_armed_flag_ptr ) );
209
+ smart_holder hld;
210
+ hld.vptr .reset (raw_ptr, []( void *) {} );
201
211
hld.vptr_is_using_noop_deleter = true ;
202
212
hld.is_populated = true ;
203
213
return hld;
@@ -227,30 +237,27 @@ struct smart_holder {
227
237
template <typename T>
228
238
static smart_holder from_raw_ptr_take_ownership (T *raw_ptr) {
229
239
ensure_pointee_is_destructible<T>(" from_raw_ptr_take_ownership" );
230
- smart_holder hld ( true ) ;
231
- hld.vptr .reset (raw_ptr, guarded_builtin_delete <T>(hld. vptr_deleter_armed_flag_ptr ));
240
+ smart_holder hld;
241
+ hld.vptr .reset (raw_ptr, make_guarded_builtin_delete <T>(true ));
232
242
hld.vptr_is_using_builtin_delete = true ;
233
243
hld.is_populated = true ;
234
244
return hld;
235
245
}
236
246
237
247
// Caller is responsible for ensuring preconditions (SMART_HOLDER_WIP: details).
238
248
void disown () {
239
- *vptr_deleter_armed_flag_ptr = false ;
240
- is_disowned = true ;
249
+ reset_vptr_deleter_armed_flag ( false ) ;
250
+ is_disowned = true ;
241
251
}
242
252
243
253
// Caller is responsible for ensuring preconditions (SMART_HOLDER_WIP: details).
244
254
void reclaim_disowned () {
245
- *vptr_deleter_armed_flag_ptr = true ;
246
- is_disowned = false ;
255
+ reset_vptr_deleter_armed_flag ( true ) ;
256
+ is_disowned = false ;
247
257
}
248
258
249
259
// Caller is responsible for ensuring preconditions (SMART_HOLDER_WIP: details).
250
- void release_disowned () {
251
- vptr.reset ();
252
- vptr_deleter_armed_flag_ptr.reset ();
253
- }
260
+ void release_disowned () { vptr.reset (); }
254
261
255
262
// SMART_HOLDER_WIP: review this function.
256
263
void ensure_can_release_ownership (const char *context = " ensure_can_release_ownership" ) {
@@ -261,7 +268,7 @@ struct smart_holder {
261
268
262
269
// Caller is responsible for ensuring preconditions (SMART_HOLDER_WIP: details).
263
270
void release_ownership () {
264
- *vptr_deleter_armed_flag_ptr = false ;
271
+ reset_vptr_deleter_armed_flag ( false ) ;
265
272
release_disowned ();
266
273
}
267
274
@@ -275,15 +282,13 @@ struct smart_holder {
275
282
276
283
template <typename T, typename D>
277
284
static smart_holder from_unique_ptr (std::unique_ptr<T, D> &&unq_ptr) {
278
- smart_holder hld ( true ) ;
285
+ smart_holder hld;
279
286
hld.rtti_uqp_del = &typeid (D);
280
287
hld.vptr_is_using_builtin_delete = is_std_default_delete<T>(*hld.rtti_uqp_del );
281
288
if (hld.vptr_is_using_builtin_delete ) {
282
- hld.vptr .reset (unq_ptr.get (),
283
- guarded_builtin_delete<T>(hld.vptr_deleter_armed_flag_ptr ));
289
+ hld.vptr .reset (unq_ptr.get (), make_guarded_builtin_delete<T>(true ));
284
290
} else {
285
- hld.vptr .reset (unq_ptr.get (),
286
- guarded_custom_deleter<T, D>(hld.vptr_deleter_armed_flag_ptr ));
291
+ hld.vptr .reset (unq_ptr.get (), make_guarded_custom_deleter<T, D>(true ));
287
292
}
288
293
unq_ptr.release ();
289
294
hld.is_populated = true ;
0 commit comments