@@ -13,6 +13,9 @@ struct default_deleter {
1313 void operator () (std::nullptr_t ) {}
1414};
1515
16+ template <typename T>
17+ class weak_ptr ;
18+
1619// / std::unique_ptr that can be observed by std::weak_ptr
1720/* * This smart pointer mimics the interface of std::unique_ptr, in that
1821* it is movable but not copiable. The smart pointer holds exclusive
@@ -26,9 +29,12 @@ struct default_deleter {
2629* will optimise as a single heap allocation with the pointed object (as
2730* std::make_shared() does for std::shared_ptr).
2831*
29- * Other notable differences (either limitations imposed by the current
32+ * Other notable points (either limitations imposed by the current
3033* implementation, or features not implemented simply because of lack of
3134* motivation):
35+ * - because of the unique ownership, weak pointers locking cannot extend
36+ * the lifetime of the pointed object, hence observable_unique_ptr provides
37+ * less thread-safety compared to std::shared_ptr.
3238* - observable_unique_ptr does not support arrays.
3339* - observable_unique_ptr does not allow custom allocators.
3440* - observable_unique_ptr does not have a release() function to let go of
@@ -55,10 +61,14 @@ class observable_unique_ptr : private std::shared_ptr<T> {
5561 template <typename U, typename D>
5662 friend class observable_unique_ptr ;
5763
64+ // Friendship is required for access to std::shared_ptr base
65+ template <typename U>
66+ friend class weak_ptr ;
67+
5868public:
5969 // Import members from std::shared_ptr
6070 using typename std::shared_ptr<T>::element_type;
61- using typename std::shared_ptr <T>::weak_type ;
71+ using weak_type = weak_ptr <T>;
6272
6373 using std::shared_ptr<T>::get;
6474 using std::shared_ptr<T>::operator *;
@@ -273,6 +283,86 @@ bool operator!= (const observable_unique_ptr<T,Deleter>& first,
273283 return first.get () != second.get ();
274284}
275285
286+ // / std::weak_ptr that observes an oup::observable_unique_ptr
287+ /* * \see observable_unique_ptr
288+ */
289+ template <typename T>
290+ class weak_ptr : private std ::weak_ptr<T> {
291+ public:
292+ // Import members from std::shared_ptr
293+ using typename std::weak_ptr<T>::element_type;
294+
295+ using std::weak_ptr<T>::reset;
296+ using std::weak_ptr<T>::swap;
297+
298+ // / Default constructor (null pointer).
299+ weak_ptr () = default ;
300+
301+ // / Create a weak pointer from an owning pointer.
302+ weak_ptr (const observable_unique_ptr<T>& owner) : std::weak_ptr<T>(owner) {}
303+
304+ // / Copy an existing weak_ptr instance
305+ /* * \param value The existing weak pointer to copy
306+ */
307+ template <typename U>
308+ weak_ptr (const weak_ptr<U>& value) noexcept :
309+ std::weak_ptr<T>(static_cast <std::weak_ptr<U>&>(value)) {}
310+
311+ // / Move from an existing weak_ptr instance
312+ /* * \param value The existing weak pointer to move from
313+ * \note After this observable_unique_ptr is created, the source
314+ * pointer is set to null.
315+ */
316+ template <typename U>
317+ weak_ptr (weak_ptr<U>&& value) noexcept :
318+ std::weak_ptr<T>(std::move(static_cast <std::weak_ptr<U>&>(value))) {}
319+
320+ // / Point to another owning pointer.
321+ weak_ptr& operator =(const observable_unique_ptr<T>& owner) {
322+ std::weak_ptr<T>::operator =(owner);
323+ return *this ;
324+ }
325+
326+ // / Copy an existing weak_ptr instance
327+ /* * \param value The existing weak pointer to copy
328+ */
329+ template <typename U>
330+ weak_ptr& operator =(const weak_ptr<U>& value) noexcept {
331+ std::weak_ptr<T>::operator =(static_cast <std::weak_ptr<U>&>(value));
332+ return *this ;
333+ }
334+
335+ // / Move from an existing weak_ptr instance
336+ /* * \param value The existing weak pointer to move from
337+ * \note After the assignment is complete, the source
338+ * pointer is set to null and looses ownership.
339+ */
340+ template <typename U>
341+ weak_ptr& operator =(weak_ptr<U>&& value) noexcept {
342+ std::weak_ptr<T>::operator =(std::move (static_cast <std::weak_ptr<U>&>(value)));
343+ return *this ;
344+ }
345+
346+ // / Get a non-owning raw pointer to the pointed object, or nullptr if deleted.
347+ /* * \return 'nullptr' if expired() is 'true', or the pointed object otherwise
348+ * \note Contrary to std::weak_ptr::lock(), this does not extend the lifetime
349+ * of the pointed object. Therefore, when calling this function, you must
350+ * make sure that the owning observable_unique_ptr will not be reset until
351+ * you are done using the raw pointer.
352+ */
353+ T* lock () const noexcept {
354+ return std::weak_ptr<T>::lock ().get ();
355+ }
356+
357+ // Copiable
358+ weak_ptr (const weak_ptr&) = default ;
359+ weak_ptr& operator =(const weak_ptr&) = default ;
360+ // Movable
361+ weak_ptr (weak_ptr&&) = default ;
362+ weak_ptr& operator =(weak_ptr&&) = default ;
363+ };
364+
365+
276366}
277367
278368#endif
0 commit comments