1111#define BOOST_CAPY_NEUNIQUE_PTR_HPP
1212
1313#include < boost/capy/detail/config.hpp>
14+ #include < boost/assert.hpp>
1415#include < cstddef>
1516#include < functional>
1617#include < memory>
@@ -24,6 +25,33 @@ namespace detail {
2425
2526// ----------------------------------------------------------
2627
28+ template <class U >
29+ auto try_delete (U* p, int ) noexcept
30+ -> decltype(sizeof (U), void())
31+ {
32+ delete p;
33+ }
34+
35+ template <class U >
36+ void try_delete (U*, long ) noexcept
37+ {
38+ // Incomplete type - should never reach here
39+ std::terminate ();
40+ }
41+
42+ template <class U >
43+ auto try_delete_array (U* p, int ) noexcept
44+ -> decltype(sizeof (U), void())
45+ {
46+ delete[] p;
47+ }
48+
49+ template <class U >
50+ void try_delete_array (U*, long ) noexcept
51+ {
52+ std::terminate ();
53+ }
54+
2755/* * Storage wrapper applying empty base optimization.
2856
2957 When `T` is empty and non-final, inherits from it to
@@ -253,6 +281,12 @@ struct control_block_array final
253281 std::size_t size;
254282 // Flexible array member follows
255283
284+ explicit control_block_array (A const & a)
285+ : alloc_storage(alloc_type(a))
286+ , size(0 )
287+ {
288+ }
289+
256290 alloc_type& get_alloc () noexcept
257291 {
258292 return alloc_storage::get ();
@@ -489,10 +523,11 @@ class neunique_ptr
489523 : ptr_(p)
490524 , cb_(other.cb_)
491525 {
526+ // aliasing requires control block; use allocate_neunique
527+ BOOST_ASSERT ((other.cb_ != nullptr || other.ptr_ == nullptr ));
492528 other.ptr_ = nullptr ;
493529 other.cb_ = nullptr ;
494530 }
495-
496531 /* * Move constructor.
497532
498533 Takes ownership from `other`. After construction,
@@ -550,7 +585,7 @@ class neunique_ptr
550585 if (cb_)
551586 cb_->destroy_and_deallocate ();
552587 else if (ptr_)
553- delete ptr_;
588+ detail::try_delete ( ptr_, 0 ) ;
554589 }
555590
556591 // ------------------------------------------------------
@@ -577,7 +612,7 @@ class neunique_ptr
577612 if (cb_)
578613 cb_->destroy_and_deallocate ();
579614 else if (ptr_)
580- delete ptr_;
615+ detail::try_delete ( ptr_, 0 ) ;
581616 ptr_ = other.ptr_ ;
582617 cb_ = other.cb_ ;
583618 other.ptr_ = nullptr ;
@@ -648,7 +683,7 @@ class neunique_ptr
648683 if (cb_)
649684 cb_->destroy_and_deallocate ();
650685 else if (ptr_)
651- delete ptr_;
686+ detail::try_delete ( ptr_, 0 ) ;
652687 ptr_ = p;
653688 cb_ = nullptr ;
654689 }
@@ -903,6 +938,8 @@ class neunique_ptr<T[]>
903938 : ptr_(p)
904939 , cb_(other.cb_)
905940 {
941+ // aliasing requires control block; use allocate_neunique
942+ BOOST_ASSERT ((other.cb_ != nullptr || other.ptr_ == nullptr ));
906943 other.ptr_ = nullptr ;
907944 other.cb_ = nullptr ;
908945 }
@@ -944,7 +981,7 @@ class neunique_ptr<T[]>
944981 if (cb_)
945982 cb_->destroy_and_deallocate ();
946983 else if (ptr_)
947- delete[] ptr_;
984+ detail::try_delete_array ( ptr_, 0 ) ;
948985 }
949986
950987 // ------------------------------------------------------
@@ -971,7 +1008,7 @@ class neunique_ptr<T[]>
9711008 if (cb_)
9721009 cb_->destroy_and_deallocate ();
9731010 else if (ptr_)
974- delete[] ptr_;
1011+ detail::try_delete_array ( ptr_, 0 ) ;
9751012 ptr_ = other.ptr_ ;
9761013 cb_ = other.cb_ ;
9771014 other.ptr_ = nullptr ;
@@ -1000,6 +1037,22 @@ class neunique_ptr<T[]>
10001037 //
10011038 // ------------------------------------------------------
10021039
1040+ /* * Replace the owned array.
1041+
1042+ Releases the currently owned array.
1043+
1044+ @post `get() == nullptr`
1045+ */
1046+ void reset () noexcept
1047+ {
1048+ if (cb_)
1049+ cb_->destroy_and_deallocate ();
1050+ else if (ptr_)
1051+ detail::try_delete_array (ptr_, 0 );
1052+ ptr_ = nullptr ;
1053+ cb_ = nullptr ;
1054+ }
1055+
10031056 /* * Replace the owned array.
10041057
10051058 Releases the currently owned array and takes
@@ -1013,7 +1066,7 @@ class neunique_ptr<T[]>
10131066 template <class U , class = typename std::enable_if<
10141067 std::is_same<U, T*>::value ||
10151068 std::is_same<U, std::nullptr_t >::value>::type>
1016- void reset (U p = nullptr ) noexcept
1069+ void reset (U p) noexcept
10171070 {
10181071 if (cb_)
10191072 cb_->destroy_and_deallocate ();
@@ -1232,9 +1285,7 @@ allocate_neunique(A const& a, std::size_t n)
12321285 auto guard = detail::make_scope_guard (
12331286 [&]{ alloc_traits::deallocate (alloc, cb, units); });
12341287
1235- ::new (static_cast <void *>(cb)) cb_type ();
1236- cb->get_alloc () = alloc;
1237- cb->size = 0 ;
1288+ ::new (static_cast <void *>(cb)) cb_type (a);
12381289
12391290 U* arr = cb->get ();
12401291 for (std::size_t i = 0 ; i < n; ++i)
0 commit comments