/** * @file * Declares the base class for scoped resources. */ #pragma once #include <functional> namespace leatherman { namespace util { /** * Simple class that is used for the RAII pattern. * Used to scope a resource. When it goes out of scope, a deleter * function is called to delete the resource. * This type can be moved but cannot be copied. * @tparam T The type of resource being scoped. */ template<typename T> struct scoped_resource { /** * Constructs an uninitialized scoped_resource. * Can be initialized via move assignment. */ scoped_resource() : _resource(), _deleter(nullptr) { } /** * Constructs a scoped_resource. * Takes ownership of the given resource. * @param resource The resource to scope. * @param deleter The function to call when the resource goes out of scope. */ scoped_resource(T resource, std::function<void(T&)> deleter) : _resource(std::move(resource)), _deleter(deleter) { } /** * Prevents the scoped_resource from being copied. */ explicit scoped_resource(scoped_resource<T> const&) = delete; /** * Prevents the scoped_resource from being copied. * @returns Returns this scoped_resource. */ scoped_resource& operator=(scoped_resource<T> const&) = delete; /** * Moves the given scoped_resource into this scoped_resource. * @param other The scoped_resource to move into this scoped_resource. */ scoped_resource(scoped_resource<T>&& other) { *this = std::move(other); } /** * Moves the given scoped_resource into this scoped_resource. * @param other The scoped_resource to move into this scoped_resource. * @return Returns this scoped_resource. */ scoped_resource& operator=(scoped_resource<T>&& other) { release(); _resource = std::move(other._resource); _deleter = std::move(other._deleter); // Ensure the deleter is in a known "empty" state; we can't rely on default move semantics for that other._deleter = nullptr; return *this; } /** * Destructs a scoped_resource. */ ~scoped_resource() { release(); } /** * Implicitly casts to T&. * @return Returns reference-to-T. */ operator T&() { return _resource; } /** * Implicitly casts to T const&. * @return Returns const-reference-to-T. */ operator T const&() const { return _resource; } /** * Releases the resource before destruction. */ void release() { if (_deleter) { _deleter(_resource); _deleter = std::function<void(T&)>(); } } protected: /** * Stores the resource being scoped. */ T _resource; /** * Stores the function to call when the resource goes out of scope. */ std::function<void(T&)> _deleter; private: void* operator new(size_t) = delete; void operator delete(void*) = delete; void* operator new[](size_t) = delete; void operator delete[](void* ptr) = delete; }; }} // namespace leatherman::util