Skip to content

Commit 15a8113

Browse files
authored
[c++] Add a non-destructed type (grpc#30491)
* [c++] Add a non-destructed type * Automated change: Fix sanity tests * Automated change: Fix sanity tests * comment Co-authored-by: ctiller <[email protected]>
1 parent 3d2e503 commit 15a8113

14 files changed

+365
-2
lines changed

BUILD

+11
Original file line numberDiff line numberDiff line change
@@ -1184,6 +1184,16 @@ grpc_cc_library(
11841184
],
11851185
)
11861186

1187+
grpc_cc_library(
1188+
name = "no_destruct",
1189+
language = "c++",
1190+
public_hdrs = ["src/core/lib/gprpp/no_destruct.h"],
1191+
deps = [
1192+
"construct_destruct",
1193+
"gpr_base",
1194+
],
1195+
)
1196+
11871197
grpc_cc_library(
11881198
name = "orphanable",
11891199
language = "c++",
@@ -7288,6 +7298,7 @@ grpc_cc_library(
72887298
"gpr_base",
72897299
"json",
72907300
"json_args",
7301+
"no_destruct",
72917302
"time",
72927303
],
72937304
)

CMakeLists.txt

+90
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

build_autogenerated.yaml

+94
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gRPC-C++.podspec

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gRPC-Core.podspec

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

grpc.gemspec

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.xml

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/core/lib/gprpp/no_destruct.h

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// Copyright 2022 gRPC 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+
// http://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+
#ifndef GRPC_CORE_LIB_GPRPP_NO_DESTRUCT_H
16+
#define GRPC_CORE_LIB_GPRPP_NO_DESTRUCT_H
17+
18+
#include <grpc/support/port_platform.h>
19+
20+
#include <utility>
21+
22+
#include "src/core/lib/gprpp/construct_destruct.h"
23+
24+
namespace grpc_core {
25+
26+
// NoDestruct<T> is a wrapper around an object of type T that:
27+
// - stores the value inline - no heap allocation
28+
// - is non-copyable
29+
// - is eagerly constructed (i.e. the constructor is called when NoDestruct is
30+
// constructed)
31+
// - *NEVER* calls ~T()
32+
// It's useful in cases where no ordering can be assumed between destructors of
33+
// objects that need to refer to each other - such as at program destruction
34+
// time.
35+
// Examples:
36+
// // globally available object:
37+
// static NoDestruct<Foo> g_foo(1, "foo", 2.0);
38+
// // used as:
39+
// g_foo->DoSomething();
40+
// // singleton function:
41+
// Bar* BarSingleton() {
42+
// static NoDestruct<Bar> bar(1, "bar", 2.0);
43+
// return &*bar;
44+
// }
45+
// The globally available version is constructed at program startup, and the
46+
// singleton version is constructed at the first call to BarSingleton().
47+
// Neither Foo nor Bar instance will be destructed.
48+
template <typename T>
49+
class NoDestruct {
50+
public:
51+
template <typename... Args>
52+
explicit NoDestruct(Args&&... args) {
53+
static_assert(std::is_trivially_destructible<NoDestruct<T>>::value,
54+
"NoDestruct must be trivially destructible");
55+
Construct(reinterpret_cast<T*>(&space_), std::forward<Args>(args)...);
56+
}
57+
NoDestruct(const NoDestruct&) = delete;
58+
NoDestruct& operator=(const NoDestruct&) = delete;
59+
~NoDestruct() = default;
60+
61+
T* operator->() { return reinterpret_cast<T*>(&space_); }
62+
const T* operator->() const { return *reinterpret_cast<const T*>(&space_); }
63+
T& operator*() { return *reinterpret_cast<T*>(&space_); }
64+
const T& operator*() const { return *reinterpret_cast<const T*>(&space_); }
65+
66+
private:
67+
typename std::aligned_storage<sizeof(T), alignof(T)>::type space_;
68+
};
69+
70+
// Helper for when a program desires a single instance of a default constructed
71+
// T to be always available.
72+
// T is constructed eagerly at program startup, so it's essentially free to load
73+
// the pointer to the instance.
74+
template <typename T>
75+
class NoDestructSingleton {
76+
public:
77+
static T* Get() { return &*value_; }
78+
79+
private:
80+
static NoDestruct<T> value_;
81+
};
82+
83+
template <typename T>
84+
NoDestruct<T> NoDestructSingleton<T>::value_;
85+
86+
} // namespace grpc_core
87+
88+
#endif // GRPC_CORE_LIB_GPRPP_NO_DESTRUCT_H

src/core/lib/json/json_object_loader.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "absl/strings/string_view.h"
3232
#include "absl/types/optional.h"
3333

34+
#include "src/core/lib/gprpp/no_destruct.h"
3435
#include "src/core/lib/gprpp/time.h"
3536
#include "src/core/lib/json/json.h"
3637
#include "src/core/lib/json/json_args.h"
@@ -354,8 +355,7 @@ class AutoLoader<absl::optional<T>> final : public LoaderInterface {
354355
// Simply keeps a static AutoLoader<T> and returns a pointer to that.
355356
template <typename T>
356357
const LoaderInterface* LoaderForType() {
357-
static const auto* loader = new AutoLoader<T>();
358-
return loader;
358+
return NoDestructSingleton<AutoLoader<T>>::Get();
359359
}
360360

361361
// Element describes one typed field to be loaded from a JSON object.

0 commit comments

Comments
 (0)