userver: userver/utils/checked_pointer.hpp Source File
Loading...
Searching...
No Matches
checked_pointer.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/utils/checked_pointer.hpp
4/// @brief @copybrief utils::CheckedPtr
5
6#include <stdexcept>
7
8#include <userver/utils/assert.hpp>
9
10USERVER_NAMESPACE_BEGIN
11
12namespace utils {
13
14/// @ingroup userver_universal userver_containers
15///
16/// @brief Utility template for returning a pointer to an object that
17/// is owned by someone else; throws std::runtime_error if nullptr is stored
18///
19/// Useful for returning cache search result.
20template <typename T>
22public:
23 /* implicit */ constexpr CheckedPtr(std::nullptr_t) noexcept : ptr_{nullptr} {}
24 explicit constexpr CheckedPtr(T* ptr) noexcept : ptr_{ptr} {}
25
26 explicit constexpr operator bool() const noexcept {
27#ifndef NDEBUG
28 checked_ = true;
29#endif
30 return ptr_;
31 }
32
33 T* Get() const& {
34 CheckPointer();
35 return ptr_;
36 }
37
38 T* Get() && { RvalueDisabled(); }
39
40 T* operator->() const& { return Get(); }
41 T* operator->() && { RvalueDisabled(); }
42
43 T& operator*() const& { return *Get(); }
44 T& operator*() && { RvalueDisabled(); }
45
46private:
47 [[noreturn]] void RvalueDisabled() {
48 static_assert(!sizeof(T), "Don't use temporary CheckedPtr, check it first, then dereference");
49 std::abort();
50 }
51 void CheckPointer() const {
52#ifndef NDEBUG
53 UASSERT_MSG(checked_, "CheckedPtr contents were not checked before dereferencing");
54#endif
55 if (!ptr_) throw std::runtime_error{"Empty checked_pointer"};
56 }
57#ifndef NDEBUG
58 mutable bool checked_{false};
59#endif
60 T* ptr_;
61};
62
63template <typename T>
64class CheckedPtr<T&> {
65 static_assert(!sizeof(T), "Don't use CheckedPointer for references");
66};
67
68template <typename T>
69constexpr CheckedPtr<T> MakeCheckedPtr(T* ptr) noexcept {
70 return CheckedPtr<T>{ptr};
71}
72
73} // namespace utils
74
75USERVER_NAMESPACE_END