|
|
@@ -8,7 +8,6 @@
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
-#include <stdexcept>
|
|
|
#include <memory>
|
|
|
|
|
|
#include "pointer_fwd.hpp"
|
|
|
@@ -20,38 +19,33 @@ class unchecked_pointer_exception : public std::logic_error {
|
|
|
|
|
|
template <typename P> class maybe_null<not_null<P>>; // not permitted
|
|
|
|
|
|
-template <typename T>
|
|
|
+#if defined( DEBUG )
|
|
|
+#define set_tested( value ) tested_ = value
|
|
|
+#else
|
|
|
+#define set_tested( _ )
|
|
|
+#endif
|
|
|
+
|
|
|
+template <typename P>
|
|
|
class maybe_null {
|
|
|
public:
|
|
|
- using element_type = typename std::pointer_traits<T>::element_type;
|
|
|
+ using element_type = typename std::pointer_traits<P>::element_type;
|
|
|
using pointer = element_type *;
|
|
|
using reference = element_type &;
|
|
|
|
|
|
maybe_null() noexcept : _ptr(nullptr) {}
|
|
|
- maybe_null(T const & p) noexcept(std::is_nothrow_copy_constructible<T>::value) : _ptr(p) { }
|
|
|
- maybe_null(T && p) noexcept(std::is_nothrow_move_constructible<T>::value) : _ptr(std::move(p)) { }
|
|
|
- maybe_null(maybe_null const&) noexcept(std::is_nothrow_copy_constructible<T>::value) = default;
|
|
|
-
|
|
|
+ maybe_null(P const & p) noexcept(detail::is_nt_cc<P>::value) : _ptr(p) { }
|
|
|
+ maybe_null(P && p) noexcept(detail::is_nt_mc<P>::value) : _ptr(std::move(p)) { }
|
|
|
+ maybe_null(maybe_null const&) noexcept(detail::is_nt_cc<P>::value) = default;
|
|
|
+ maybe_null(maybe_null &&) noexcept(detail::is_nt_mc<P>::value) = default;
|
|
|
template <typename Y>
|
|
|
- explicit operator maybe_null<Y>() const noexcept(std::is_nothrow_copy_constructible<Y>::value) {
|
|
|
- return _ptr;
|
|
|
- }
|
|
|
+ maybe_null(maybe_null<Y> const&other) noexcept(detail::is_nt_c<P, Y>::value)
|
|
|
+ : _ptr(other._ptr) { set_tested(other.tested_); }
|
|
|
|
|
|
- maybe_null& operator=(maybe_null const&) noexcept = default;
|
|
|
- template <typename Y> maybe_null& operator=(maybe_null<Y> const&other) noexcept {
|
|
|
- if (_ptr != other._ptr) {
|
|
|
- _ptr = other._ptr;
|
|
|
-#if defined( DEBUG )
|
|
|
- tested_ = other.tested_;
|
|
|
-#endif
|
|
|
- }
|
|
|
- return *this;
|
|
|
- }
|
|
|
+ maybe_null& operator=(maybe_null const&) noexcept(detail::is_nt_ca<P>::value) = default;
|
|
|
+ maybe_null& operator=(maybe_null &&) noexcept(detail::is_nt_ma<P>::value) = default;
|
|
|
|
|
|
operator bool() const noexcept {
|
|
|
-#if defined( DEBUG )
|
|
|
- tested_ = true;
|
|
|
-#endif
|
|
|
+ set_tested(true);
|
|
|
return static_cast<bool>(_ptr);
|
|
|
}
|
|
|
|
|
|
@@ -59,21 +53,23 @@ public:
|
|
|
pointer operator->() const /*throw(unchecked_pointer_exception)*/ {
|
|
|
return std::addressof(operator*());
|
|
|
}
|
|
|
-#if defined( DEBUG )
|
|
|
reference operator*() const /*throw(unchecked_pointer_exception)*/ {
|
|
|
- if ( !tested_ ) { throw unchecked_pointer_exception{"did not verify that pointer was non-null"}; }
|
|
|
- return *_ptr;
|
|
|
- }
|
|
|
-#else
|
|
|
- reference operator*() const noexcept {
|
|
|
+#if defined( DEBUG )
|
|
|
+ if ( ! tested_ ) { throw unchecked_pointer_exception{"did not verify that pointer was non-null"}; }
|
|
|
+#endif
|
|
|
+ if ( ! _ptr ) { throw null_pointer_exception{"dereferencing maybe_null in null state"}; }
|
|
|
return *_ptr;
|
|
|
}
|
|
|
-#endif
|
|
|
+
|
|
|
+ void reset( P const & p ) { operator=(maybe_null(p)); }
|
|
|
+ void reset( P && p = P() ) { operator=(maybe_null(std::forward(p))); }
|
|
|
private:
|
|
|
- T _ptr;
|
|
|
+ template <typename Y> friend class maybe_null;
|
|
|
+ P _ptr;
|
|
|
#if defined( DEBUG )
|
|
|
mutable bool tested_ = false;
|
|
|
#endif
|
|
|
};
|
|
|
|
|
|
+#undef set_tested
|
|
|
POINTER_TEMPLATE_COMPARE( maybe_null )
|