Created
September 8, 2014 10:55
-
-
Save cjxgm/ea0b8b912f5321b1ba52 to your computer and use it in GitHub Desktop.
c++ raii unique resource
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cstddef> | |
#include <type_traits> | |
#include <utility> | |
#include <functional> | |
#include <stdexcept> | |
#include <iostream> | |
using std::cin; | |
using std::cout; | |
using std::cerr; | |
using std::endl; | |
namespace tue | |
{ | |
template <class T, T null=T{}> | |
struct unique_res | |
{ | |
using self_type = unique_res; | |
using self_ref = self_type &; | |
using self_rref = self_type &&; | |
using self_cref = self_type const&; | |
using value_type = std::remove_reference_t<T>; | |
using deleter_type = std::function<void(value_type)>; | |
using deleter_cref = deleter_type const&; | |
using deleter_ref = deleter_type &; | |
static constexpr auto null_value = null; | |
static_assert(std::is_pod<value_type>(), "T must be a plain-old-data."); | |
// constructor | |
unique_res() : unique_res(null_value, {}) {} | |
unique_res(value_type value, deleter_type deleter) | |
: value(value), deleter(deleter) {} | |
// observer | |
value_type get () const { return value ; } | |
deleter_ref & get_deleter() { return deleter; } | |
deleter_cref& get_deleter() const { return deleter; } | |
operator value_type() const { return get(); } | |
operator bool () const { return (get() != null_value); } | |
// destructor | |
~unique_res() | |
{ | |
if (get() == null_value) return; | |
if (!get_deleter()) | |
throw std::logic_error{"no deleter: may cause memory leak"}; | |
get_deleter()(value); | |
} | |
// modifier | |
value_type release() | |
{ | |
auto x = value; | |
value = null_value; | |
return x; | |
} | |
void swap(self_ref other) | |
{ | |
std::swap(value, other.value); | |
std::swap(deleter, other.deleter); | |
} | |
void swap(self_rref other) { swap(other); } | |
void reset(value_type v=null_value) { swap({v, deleter}); } | |
// copy-move | |
unique_res(self_cref) = delete; | |
self_ref operator=(self_cref) = delete; | |
unique_res(self_rref other) : unique_res() { swap(other); } | |
self_ref operator=(self_rref other) | |
{ | |
self_type empty; | |
swap(empty); | |
swap(other); | |
return *this; | |
} | |
private: | |
value_type value; | |
deleter_type deleter; | |
}; | |
} | |
int main() | |
{ | |
auto deleter_one = [](int x) { cout << "1: " << x << endl; }; | |
auto deleter_two = [](int x) { cout << "1: " << x << endl; }; | |
using unique_one = tue::unique_res<int, 1>; | |
unique_one one(1, deleter_one); | |
unique_one two(1, deleter_two); | |
one.reset(3); | |
one.reset(2); | |
two = std::move(one); | |
one.reset(1); | |
one.reset(0); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment