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>
22 public:
23 /* implicit */ constexpr CheckedPtr(std::nullptr_t) noexcept
24 : ptr_{nullptr} {}
25 explicit constexpr CheckedPtr(T* ptr) noexcept : ptr_{ptr} {}
26
27 explicit constexpr operator bool() const noexcept {
28#ifndef NDEBUG
29 checked_ = true;
30#endif
31 return ptr_;
32 }
33
34 T* Get() const& {
35 CheckPointer();
36 return ptr_;
37 }
38
39 T* Get() && { RvalueDisabled(); }
40
41 T* operator->() const& { return Get(); }
42 T* operator->() && { RvalueDisabled(); }
43
44 T& operator*() const& { return *Get(); }
45 T& operator*() && { RvalueDisabled(); }
46
47 private:
48 [[noreturn]] void RvalueDisabled() {
49 static_assert(
50 !sizeof(T),
51 "Don't use temporary CheckedPtr, check it first, then dereference");
52 std::abort();
53 }
54 void CheckPointer() const {
55#ifndef NDEBUG
56 UASSERT_MSG(checked_,
57 "CheckedPtr contents were not checked before dereferencing");
58#endif
59 if (!ptr_) throw std::runtime_error{"Empty checked_pointer"};
60 }
61#ifndef NDEBUG
62 mutable bool checked_{false};
63#endif
64 T* ptr_;
65};
66
67template <typename T>
68class CheckedPtr<T&> {
69 static_assert(!sizeof(T), "Don't use CheckedPointer for references");
70};
71
72template <typename T>
73constexpr CheckedPtr<T> MakeCheckedPtr(T* ptr) noexcept {
74 return CheckedPtr<T>{ptr};
75}
76
77} // namespace utils
78
79USERVER_NAMESPACE_END