109 lines · c
1// -*- C++ -*-2//===----------------------------------------------------------------------===//3//4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.5// See https://llvm.org/LICENSE.txt for license information.6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception7//8//===----------------------------------------------------------------------===//9 10#ifndef _LIBCPP___CXX03___MEMORY_ALLOCATION_GUARD_H11#define _LIBCPP___CXX03___MEMORY_ALLOCATION_GUARD_H12 13#include <__cxx03/__config>14#include <__cxx03/__memory/addressof.h>15#include <__cxx03/__memory/allocator_traits.h>16#include <__cxx03/__utility/move.h>17#include <__cxx03/cstddef>18 19#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)20# pragma GCC system_header21#endif22 23_LIBCPP_PUSH_MACROS24#include <__cxx03/__undef_macros>25 26_LIBCPP_BEGIN_NAMESPACE_STD27 28// Helper class to allocate memory using an Allocator in an exception safe29// manner.30//31// The intended usage of this class is as follows:32//33// 034// 1 __allocation_guard<SomeAllocator> guard(alloc, 10);35// 2 do_some_initialization_that_may_throw(guard.__get());36// 3 save_allocated_pointer_in_a_noexcept_operation(guard.__release_ptr());37// 438//39// If line (2) throws an exception during initialization of the memory, the40// guard's destructor will be called, and the memory will be released using41// Allocator deallocation. Otherwise, we release the memory from the guard on42// line (3) in an operation that can't throw -- after that, the guard is not43// responsible for the memory anymore.44//45// This is similar to a unique_ptr, except it's easier to use with a46// custom allocator.47template <class _Alloc>48struct __allocation_guard {49 using _Pointer = typename allocator_traits<_Alloc>::pointer;50 using _Size = typename allocator_traits<_Alloc>::size_type;51 52 template <class _AllocT> // we perform the allocator conversion inside the constructor53 _LIBCPP_HIDE_FROM_ABI explicit __allocation_guard(_AllocT __alloc, _Size __n)54 : __alloc_(std::move(__alloc)),55 __n_(__n),56 __ptr_(allocator_traits<_Alloc>::allocate(__alloc_, __n_)) // initialization order is important57 {}58 59 _LIBCPP_HIDE_FROM_ABI ~__allocation_guard() _NOEXCEPT { __destroy(); }60 61 _LIBCPP_HIDE_FROM_ABI __allocation_guard(const __allocation_guard&) = delete;62 _LIBCPP_HIDE_FROM_ABI __allocation_guard(__allocation_guard&& __other) _NOEXCEPT63 : __alloc_(std::move(__other.__alloc_)),64 __n_(__other.__n_),65 __ptr_(__other.__ptr_) {66 __other.__ptr_ = nullptr;67 }68 69 _LIBCPP_HIDE_FROM_ABI __allocation_guard& operator=(const __allocation_guard& __other) = delete;70 _LIBCPP_HIDE_FROM_ABI __allocation_guard& operator=(__allocation_guard&& __other) _NOEXCEPT {71 if (std::addressof(__other) != this) {72 __destroy();73 74 __alloc_ = std::move(__other.__alloc_);75 __n_ = __other.__n_;76 __ptr_ = __other.__ptr_;77 __other.__ptr_ = nullptr;78 }79 80 return *this;81 }82 83 _LIBCPP_HIDE_FROM_ABI _Pointer84 __release_ptr() _NOEXCEPT { // not called __release() because it's a keyword in objective-c++85 _Pointer __tmp = __ptr_;86 __ptr_ = nullptr;87 return __tmp;88 }89 90 _LIBCPP_HIDE_FROM_ABI _Pointer __get() const _NOEXCEPT { return __ptr_; }91 92private:93 _LIBCPP_HIDE_FROM_ABI void __destroy() _NOEXCEPT {94 if (__ptr_ != nullptr) {95 allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __n_);96 }97 }98 99 _Alloc __alloc_;100 _Size __n_;101 _Pointer __ptr_;102};103 104_LIBCPP_END_NAMESPACE_STD105 106_LIBCPP_POP_MACROS107 108#endif // _LIBCPP___CXX03___MEMORY_ALLOCATION_GUARD_H109