WPILibC++ 2023.4.3
never_destroyed.h
Go to the documentation of this file.
1#pragma once
2
3#include <new>
4#include <type_traits>
5#include <utility>
6
8
9namespace drake {
10
11/// Wraps an underlying type T such that its storage is a direct member field
12/// of this object (i.e., without any indirection into the heap), but *unlike*
13/// most member fields T's destructor is never invoked.
14///
15/// This is especially useful for function-local static variables that are not
16/// trivially destructable. We shouldn't call their destructor at program exit
17/// because of the "indeterminate order of ... destruction" as mentioned in
18/// cppguide's
19/// <a href="https://drake.mit.edu/styleguide/cppguide.html#Static_and_Global_Variables">Static
20/// and Global Variables</a> section, but other solutions to this problem place
21/// the objects on the heap through an indirection.
22///
23/// Compared with other approaches, this mechanism more clearly describes the
24/// intent to readers, avoids "possible leak" warnings from memory-checking
25/// tools, and is probably slightly faster.
26///
27/// Example uses:
28///
29/// The singleton pattern:
30/// @code
31/// class Singleton {
32/// public:
33/// DRAKE_NO_COPY_NO_MOVE_NO_ASSIGN(Singleton)
34/// static Singleton& getInstance() {
35/// static never_destroyed<Singleton> instance;
36/// return instance.access();
37/// }
38/// private:
39/// friend never_destroyed<Singleton>;
40/// Singleton() = default;
41/// };
42/// @endcode
43///
44/// A lookup table, created on demand the first time its needed, and then
45/// reused thereafter:
46/// @code
47/// enum class Foo { kBar, kBaz };
48/// Foo ParseFoo(const std::string& foo_string) {
49/// using Dict = std::unordered_map<std::string, Foo>;
50/// static const drake::never_destroyed<Dict> string_to_enum{
51/// std::initializer_list<Dict::value_type>{
52/// {"bar", Foo::kBar},
53/// {"baz", Foo::kBaz},
54/// }
55/// };
56/// return string_to_enum.access().at(foo_string);
57/// }
58/// @endcode
59///
60/// In cases where computing the static data is more complicated than an
61/// initializer_list, you can use a temporary lambda to populate the value:
62/// @code
63/// const std::vector<double>& GetConstantMagicNumbers() {
64/// static const drake::never_destroyed<std::vector<double>> result{[]() {
65/// std::vector<double> prototype;
66/// std::mt19937 random_generator;
67/// for (int i = 0; i < 10; ++i) {
68/// double new_value = random_generator();
69/// prototype.push_back(new_value);
70/// }
71/// return prototype;
72/// }()};
73/// return result.access();
74/// }
75/// @endcode
76///
77/// Note in particular the `()` after the lambda. That causes it to be invoked.
78//
79// The above examples are repeated in the unit test; keep them in sync.
80template <typename T>
82 public:
84
85 /// Passes the constructor arguments along to T using perfect forwarding.
86 template <typename... Args>
87 explicit never_destroyed(Args&&... args) {
88 // Uses "placement new" to construct a `T` in `storage_`.
89 new (&storage_) T(std::forward<Args>(args)...);
90 }
91
92 /// Does nothing. Guaranteed!
93 ~never_destroyed() = default;
94
95 /// Returns the underlying T reference.
96 T& access() { return *reinterpret_cast<T*>(&storage_); }
97 const T& access() const { return *reinterpret_cast<const T*>(&storage_); }
98
99 private:
100 typename std::aligned_storage<sizeof(T), alignof(T)>::type storage_;
101};
102
103} // namespace drake
Wraps an underlying type T such that its storage is a direct member field of this object (i....
Definition: never_destroyed.h:81
T & access()
Returns the underlying T reference.
Definition: never_destroyed.h:96
~never_destroyed()=default
Does nothing. Guaranteed!
never_destroyed(Args &&... args)
Passes the constructor arguments along to T using perfect forwarding.
Definition: never_destroyed.h:87
const T & access() const
Definition: never_destroyed.h:97
type
Definition: core.h:575
Provides careful macros to selectively enable or disable the special member functions for copy-constr...
#define DRAKE_NO_COPY_NO_MOVE_NO_ASSIGN(Classname)
DRAKE_NO_COPY_NO_MOVE_NO_ASSIGN deletes the special member functions for copy-construction,...
Definition: drake_copyable.h:33
Definition: drake_assertion_error.h:6