Skip to content

Commit b965104

Browse files
committed
Added weak_ptr
1 parent f79ca93 commit b965104

File tree

1 file changed

+92
-2
lines changed

1 file changed

+92
-2
lines changed

include/oup/observable_unique_ptr.hpp

Lines changed: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
5868
public:
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

Comments
 (0)