File no_destructor.h
File List > deps > no_destructor.h
Go to the documentation of this file
// Copyright 2019 The MediaPipe Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef MEDIAPIPE_DEPS_NO_DESTRUCTOR_H_
#define MEDIAPIPE_DEPS_NO_DESTRUCTOR_H_
#include <type_traits>
#include <utility>
namespace mediapipe {
// NoDestructor<T> is a wrapper around an object of type T that
// * stores the object of type T inline inside NoDestructor<T>
// * eagerly forwards constructor arguments to it (i.e. acts like T in terms
// of construction)
// * provides access to the object of type T like a pointer via ->, *, and get()
// (note that const NoDestructor<T> works like a pointer to const T)
// * never calls T's destructor for the object
// (hence NoDestructor<T> objects created on the stack or as member variables
// will lead to memory and/or resource leaks)
//
// One key use case of NoDestructor (which in itself is not lazy) is optimizing
// the following pattern of safe on-demand construction of an object with
// non-trivial constructor in static storage without destruction ever happening:
// const std::string& MyString() {
// static std::string* x = new std::string("foo"); // note the "static"
// return *x;
// }
// By using NoDestructor we do not need to involve heap allocation and
// corresponding pointer following (and hence extra CPU cache usage/needs)
// on each access:
// const std::string& MyString() {
// static NoDestructor<std::string> x("foo");
// return *x;
// }
// Since C++11 this static-in-a-function pattern results in exactly-once,
// thread-safe, on-demand construction of an object, and very fast access
// thereafter (the cost is a few extra cycles).
// NoDestructor makes accesses even faster by storing the object inline in
// static storage.
//
// Note that:
// * Since destructor is never called, the object lives on during program exit
// and can be safely accessed by any threads that have not been joined.
// * This static-in-a-function NoDestructor usage pattern should be preferred
// to uses of gtl::LazyStaticPtr in new code.
//
// Also note that
// static NoDestructor<NonPOD> ptr(whatever);
// can safely replace
// static NonPOD* ptr = new NonPOD(whatever);
// or
// static NonPOD obj(whatever);
// at file-level scope when the safe static-in-a-function pattern is infeasible
// to use for some good reason.
// All three of the NonPOD patterns above suffer from the same issue that
// initialization of that object happens non-thread-safely at
// a globally-undefined point during initialization of static-storage objects,
// but NoDestructor<> usage provides both the safety of having the object alive
// during program exit sequence and the performance of not doing extra memory
// dereference on access.
//
template <typename T>
class NoDestructor {
public:
typedef T element_type;
// Forwards arguments to the T's constructor: calls T(args...).
template <typename... Ts,
// Disable this overload when it might collide with copy/move.
typename std::enable_if<
!std::is_same<void(typename std::decay<Ts>::type...),
void(NoDestructor)>::value,
int>::type = 0>
explicit NoDestructor(Ts&&... args) {
new (&space_) T(std::forward<Ts>(args)...);
}
// Forwards copy and move construction for T. Enables usage like this:
// static NoDestructor<std::array<std::string, 3>> x{{{"1", "2", "3"}}};
// static NoDestructor<std::vector<int>> x{{1, 2, 3}};
explicit NoDestructor(const T& x) { new (&space_) T(x); }
explicit NoDestructor(T&& x) { new (&space_) T(std::move(x)); }
// No copying.
NoDestructor(const NoDestructor&) = delete;
NoDestructor& operator=(const NoDestructor&) = delete;
// Pretend to be a smart pointer to T with deep constness.
// Never returns a null pointer.
T& operator*() { return *get(); }
T* operator->() { return get(); }
T* get() { return reinterpret_cast<T*>(&space_); }
const T& operator*() const { return *get(); }
const T* operator->() const { return get(); }
const T* get() const { return reinterpret_cast<const T*>(&space_); }
private:
typename std::aligned_storage<sizeof(T), alignof(T)>::type space_;
};
} // namespace mediapipe
#endif // MEDIAPIPE_DEPS_NO_DESTRUCTOR_H_