Coverage Report

Created: 2026-07-25 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/abseil-cpp/absl/base/no_destructor.h
Line
Count
Source
1
// Copyright 2023 The Abseil Authors.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//      https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
//
15
// -----------------------------------------------------------------------------
16
// File: no_destructor.h
17
// -----------------------------------------------------------------------------
18
//
19
// This header file defines the absl::NoDestructor<T> wrapper for defining a
20
// static type that does not need to be destructed upon program exit. Instead,
21
// such an object survives during program exit (and can be safely accessed at
22
// any time).
23
//
24
// Objects of such type, if constructed safely and under the right conditions,
25
// provide two main benefits over other alternatives:
26
//
27
//   * Global objects not normally allowed due to concerns of destruction order
28
//     (i.e. no "complex globals") can be safely allowed, provided that such
29
//     objects can be constant initialized.
30
//   * Function scope static objects can be optimized to avoid heap allocation,
31
//     pointer chasing, and allow lazy construction.
32
//
33
// See below for complete details.
34
35
36
#ifndef ABSL_BASE_NO_DESTRUCTOR_H_
37
#define ABSL_BASE_NO_DESTRUCTOR_H_
38
39
#include <new>
40
#include <type_traits>
41
#include <utility>
42
43
#include "absl/base/config.h"
44
45
namespace absl {
46
ABSL_NAMESPACE_BEGIN
47
48
// absl::NoDestructor<T>
49
//
50
// NoDestructor<T> is a wrapper around an object of type T that behaves as an
51
// object of type T but never calls T's destructor. NoDestructor<T> makes it
52
// safer and/or more efficient to use such objects in static storage contexts:
53
// as global or function scope static variables.
54
//
55
// An instance of absl::NoDestructor<T> has similar type semantics to an
56
// instance of T:
57
//
58
// * Constructs in the same manner as an object of type T through perfect
59
//   forwarding.
60
// * Provides pointer/reference semantic access to the object of type T via
61
//   `->`, `*`, and `get()`.
62
//   (Note that `const NoDestructor<T>` works like a pointer to const `T`.)
63
//
64
// An object of type NoDestructor<T> should be defined in static storage:
65
// as either a global static object, or as a function scope static variable.
66
//
67
// Additionally, NoDestructor<T> provides the following benefits:
68
//
69
// * Never calls T's destructor for the object
70
// * If the object is a function-local static variable, the type can be
71
//   lazily constructed.
72
//
73
// An object of type NoDestructor<T> is "trivially destructible" in the notion
74
// that its destructor is never run. Provided that an object of this type can be
75
// safely initialized and does not need to be cleaned up on program shutdown,
76
// NoDestructor<T> allows you to define global static variables, since Google's
77
// C++ style guide ban on such objects doesn't apply to objects that are
78
// trivially destructible.
79
//
80
// Usage as Global Static Variables
81
//
82
// NoDestructor<T> allows declaration of a global object with a non-trivial
83
// constructor in static storage without needing to add a destructor.
84
// However, such objects still need to worry about initialization order, so
85
// such objects should be const initialized:
86
//
87
//    // Global or namespace scope.
88
//    ABSL_CONST_INIT absl::NoDestructor<MyRegistry> reg{"foo", "bar", 8008};
89
//
90
// Note that if your object already has a trivial destructor, you don't need to
91
// use NoDestructor<T>.
92
//
93
// Usage as Function Scope Static Variables
94
//
95
// Function static objects will be lazily initialized within static storage:
96
//
97
//    // Function scope.
98
//    const std::string& MyString() {
99
//      static const absl::NoDestructor<std::string> x("foo");
100
//      return *x;
101
//    }
102
//
103
// For function static variables, NoDestructor avoids heap allocation and can be
104
// inlined in static storage, resulting in exactly-once, thread-safe
105
// construction of an object, and very fast access thereafter (the cost is a few
106
// extra cycles).
107
//
108
// Using NoDestructor<T> in this manner is generally better than other patterns
109
// which require pointer chasing:
110
//
111
//   // Prefer using absl::NoDestructor<T> instead for the static variable.
112
//   const std::string& MyString() {
113
//     static const std::string* x = new std::string("foo");
114
//     return *x;
115
//   }
116
//
117
template <typename T>
118
class NoDestructor {
119
 public:
120
  // Forwards arguments to the T's constructor: calls T(args...).
121
  template <typename... Ts,
122
            // Disable this overload when it might collide with copy/move.
123
            typename std::enable_if<!std::is_same<void(std::decay_t<Ts>&...),
124
                                                  void(NoDestructor&)>::value,
125
                                    int>::type = 0>
126
  explicit constexpr NoDestructor(Ts&&... args)
127
0
      : impl_(std::forward<Ts>(args)...) {}
Unexecuted instantiation: _ZN4absl12lts_2024011612NoDestructorINSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEC2IJETnNS2_9enable_ifIXntsr3std7is_sameIFvDpRu7__decayIT_EEFvRS9_EEE5valueEiE4typeELi0EEEDpOSC_
Unexecuted instantiation: _ZN4absl12lts_2024011612NoDestructorINSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEC2IJRA28_KcETnNS2_9enable_ifIXntsr3std7is_sameIFvDpRu7__decayIT_EEFvRS9_EEE5valueEiE4typeELi0EEEDpOSF_
128
129
  // Forwards copy and move construction for T. Enables usage like this:
130
  //   static NoDestructor<std::array<string, 3>> x{{{"1", "2", "3"}}};
131
  //   static NoDestructor<std::vector<int>> x{{1, 2, 3}};
132
  explicit constexpr NoDestructor(const T& x) : impl_(x) {}
133
  explicit constexpr NoDestructor(T&& x)
134
      : impl_(std::move(x)) {}
135
136
  // No copying.
137
  NoDestructor(const NoDestructor&) = delete;
138
  NoDestructor& operator=(const NoDestructor&) = delete;
139
140
  // Pretend to be a smart pointer to T with deep constness.
141
  // Never returns a null pointer.
142
  T& operator*() { return *get(); }
143
  T* operator->() { return get(); }
144
  T* get() { return impl_.get(); }
145
  const T& operator*() const { return *get(); }
146
  const T* operator->() const { return get(); }
147
0
  const T* get() const { return impl_.get(); }
148
149
 private:
150
  class DirectImpl {
151
   public:
152
    template <typename... Args>
153
    explicit constexpr DirectImpl(Args&&... args)
154
        : value_(std::forward<Args>(args)...) {}
155
    const T* get() const { return &value_; }
156
    T* get() { return &value_; }
157
158
   private:
159
    T value_;
160
  };
161
162
  class PlacementImpl {
163
   public:
164
    template <typename... Args>
165
0
    explicit PlacementImpl(Args&&... args) {
166
0
      new (&space_) T(std::forward<Args>(args)...);
167
0
    }
Unexecuted instantiation: absl::lts_20240116::NoDestructor<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::PlacementImpl::PlacementImpl<>()
Unexecuted instantiation: absl::lts_20240116::NoDestructor<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::PlacementImpl::PlacementImpl<char const (&) [28]>(char const (&) [28])
168
0
    const T* get() const {
169
0
      return Launder(reinterpret_cast<const T*>(&space_));
170
0
    }
171
    T* get() { return Launder(reinterpret_cast<T*>(&space_)); }
172
173
   private:
174
    template <typename P>
175
0
    static P* Launder(P* p) {
176
0
#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L
177
0
      return std::launder(p);
178
#elif ABSL_HAVE_BUILTIN(__builtin_launder)
179
      return __builtin_launder(p);
180
#else
181
      // When `std::launder` or equivalent are not available, we rely on
182
      // undefined behavior, which works as intended on Abseil's officially
183
      // supported platforms as of Q3 2023.
184
#if defined(__GNUC__) && !defined(__clang__)
185
#pragma GCC diagnostic push
186
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
187
#endif
188
      return p;
189
#if defined(__GNUC__) && !defined(__clang__)
190
#pragma GCC diagnostic pop
191
#endif
192
#endif
193
0
    }
194
195
    alignas(T) unsigned char space_[sizeof(T)];
196
  };
197
198
  // If the object is trivially destructible we use a member directly to avoid
199
  // potential once-init runtime initialization. It somewhat defeats the
200
  // purpose of NoDestructor in this case, but this makes the class more
201
  // friendly to generic code.
202
  std::conditional_t<std::is_trivially_destructible<T>::value, DirectImpl,
203
                     PlacementImpl>
204
      impl_;
205
};
206
207
#ifdef ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
208
// Provide 'Class Template Argument Deduction': the type of NoDestructor's T
209
// will be the same type as the argument passed to NoDestructor's constructor.
210
template <typename T>
211
NoDestructor(T) -> NoDestructor<T>;
212
#endif  // ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
213
214
ABSL_NAMESPACE_END
215
}  // namespace absl
216
217
#endif  // ABSL_BASE_NO_DESTRUCTOR_H_