Skip to content

Instantly share code, notes, and snippets.

@25077667
Created July 14, 2024 19:00
Show Gist options
  • Save 25077667/dcaccf4ecf8882ba9277ba7617076c76 to your computer and use it in GitHub Desktop.
Save 25077667/dcaccf4ecf8882ba9277ba7617076c76 to your computer and use it in GitHub Desktop.
NoThrowAllocator in C++: A standard-compliant, exception-free memory allocator for high reliability applications.
#ifndef SCC_NOTHROW_ALLOCATOR
#define SCC_NOTHROW_ALLOCATOR
#pragma once
#include <memory>
#include <limits>
#include <new>
namespace scc {
template <typename T>
struct NoThrowAllocator {
using value_type = T;
NoThrowAllocator() noexcept = default;
template <class U>
NoThrowAllocator(const NoThrowAllocator<U>&) noexcept {}
T* allocate(std::size_t n) noexcept {
if (n > std::numeric_limits<std::size_t>::max() / sizeof(T)) {
return nullptr;
}
try {
return static_cast<T*>(::operator new(n * sizeof(T), std::nothrow));
} catch (...) {
return nullptr;
}
}
void deallocate(T* ptr, std::size_t) noexcept {
::operator delete(ptr, std::nothrow);
}
template <typename U>
struct rebind {
using other = NoThrowAllocator<U>;
};
};
template <typename T, typename U>
inline bool operator==(const NoThrowAllocator<T>&, const NoThrowAllocator<U>&) noexcept {
return true;
}
template <typename T, typename U>
inline bool operator!=(const NoThrowAllocator<T>& a, const NoThrowAllocator<U>& b) noexcept {
return !(a == b);
};
} // namespace scc
// Allocator traits specialization
namespace std {
template <typename T>
struct allocator_traits<scc::NoThrowAllocator<T>> {
using allocator_type = scc::NoThrowAllocator<T>;
using value_type = typename allocator_type::value_type;
using pointer = value_type*;
using const_pointer = const value_type*;
using void_pointer = void*;
using const_void_pointer = const void*;
using difference_type = std::ptrdiff_t;
using size_type = std::size_t;
using propagate_on_container_copy_assignment = std::false_type;
using propagate_on_container_move_assignment = std::false_type;
using propagate_on_container_swap = std::false_type;
using is_always_equal = std::true_type;
template <typename U>
using rebind_alloc = typename allocator_type::template rebind<U>::other;
template <typename U>
using rebind_traits = std::allocator_traits<rebind_alloc<U>>;
static pointer allocate(allocator_type& a, size_type n) {
return a.allocate(n);
}
static void deallocate(allocator_type& a, pointer p, size_type n) {
a.deallocate(p, n);
}
template <typename U, typename... Args>
static void construct(allocator_type&, U* p, Args&&... args) {
::new(static_cast<void*>(p)) U(std::forward<Args>(args)...);
}
template <typename U>
static void destroy(allocator_type&, U* p) {
p->~U();
}
static size_type max_size(const allocator_type&) noexcept {
return std::numeric_limits<size_type>::max() / sizeof(value_type);
}
static allocator_type select_on_container_copy_construction(const allocator_type& rhs) {
return rhs;
}
};
} // namespace std
#endif // SCC_NOTHROW_ALLOCATOR
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment