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 <cstdlib>
7#include <stdexcept>
8
9#include <userver/utils/assert.hpp>
10
11USERVER_NAMESPACE_BEGIN
12
13namespace utils {
14
15/// @ingroup userver_universal userver_containers
16///
17/// @brief Utility template for returning a pointer to an object that
18/// is owned by someone else; throws std::runtime_error if nullptr is stored
19///
20/// Useful for returning cache search result.
21template <typename T>
23public:
24 /* implicit */ constexpr CheckedPtr(std::nullptr_t) noexcept : 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
47private:
48 [[noreturn]] void RvalueDisabled() {
49 static_assert(!sizeof(T), "Don't use temporary CheckedPtr, check it first, then dereference");
50 std::abort();
51 }
52 void CheckPointer() const {
53#ifndef NDEBUG
54 UASSERT_MSG(checked_, "CheckedPtr contents were not checked before dereferencing");
55#endif
56 if (!ptr_) throw std::runtime_error{"Empty checked_pointer"};
57 }
58#ifndef NDEBUG
59 mutable bool checked_{false};
60#endif
61 T* ptr_;
62};
63
64template <typename T>
65class CheckedPtr<T&> {
66 static_assert(!sizeof(T), "Don't use CheckedPointer for references");
67};
68
69template <typename T>
70constexpr CheckedPtr<T> MakeCheckedPtr(T* ptr) noexcept {
71 return CheckedPtr<T>{ptr};
72}
73
74} // namespace utils
75
76USERVER_NAMESPACE_END