c++ - How can I implement this autoscope template object better? -
i have idea auto-scoped type clean resources when leave scope or containing object destructed.
this currently:
template <typename resource, typename deleteor> struct autoscope { resource m_resource; deleteor const& m_deleteor; autoscope(resource resource, deleteor const& deleteor) : m_resource(resource) , m_deleteor(deleteor) { } operator resource() { return m_resource; } ~autoscope() { m_deleteor(m_resource); } }; template <typename resource, typename deleteor> autoscope<resource, deleteor> make_autoscope(resource resource, deleteor deleteor) { return autoscope<resource, deleteor>(resource, deleteor); }
a couple of potential/real problems see/have come across.
for each resource handled, there deletor object or pointer created. i'm not sure if optimizer junk , inline deletor functor or function pointer autoscope object not larger resource handle. i'm not sure compiler allowed to, don't think possible have deletor just passed type.
i tried pass
hicon
, function pointerdestroyicon()
, crashed. when debugging showed pointer passedmake_autoscope()
0x755225e0 {user32.dll!_destroycursor@4}
, wrong. vc++ problem (2013)? or there else wrong?
i'm using vc++ in vs2013, should portable.
edit
ok, i've thought ideas based on comments. here i've come far:
template <typename resource, typename crtp, resource invalid> struct autoscope { protected: resource m_res; public: autoscope() : m_res(invalid) { } autoscope(resource res) : m_res(res) { } autoscope(autoscope&& move) { std::swap(move.m_res, m_res); } autoscope(autoscope& copy) = delete; operator resource() const { return m_res; } resource get() const { return m_res; } resource operator =(resource res) { set(res); } void set(resource res) { static_cast<crtp*>(this)->delete_resource(); m_res = res; } resource release() { resource result = m_res; m_res = invalid; return result; } ~autoscope() { static_cast<crtp*>(this)->delete_resource(); } operator bool() const { return m_res != (resource)0; } bool valid() const { return m_res != invalid; } }; template <typename resource, bool(winapi *fn_delete)(resource), resource invalid = (resource)-1> struct autoscope_bool : public autoscope<resource, autoscope_bool<resource, fn_delete, invalid>, invalid> { typedef autoscope<resource, autoscope_bool, invalid> base; autoscope_bool() : base(invalid) { } autoscope_bool(resource res) : base(res) { } autoscope_bool(autoscope_bool&& move) : base(std::forward<autoscope_bool>(move)) { } autoscope_bool(autoscope_bool& copy) = delete; void delete_resource() { if (base::m_res && base::m_res != invalid) { verify(fn_delete(base::m_res)); base::m_res = invalid; } } }; template <typename resource, typename void(winapi *fn_delete)(resource), resource invalid = (resource)-1> struct autoscope_void : autoscope<resource, autoscope_void<resource, fn_delete, invalid>, invalid> { typedef autoscope<resource, autoscope_void, invalid> base; autoscope_void() : base(invalid) { } autoscope_void(resource res) : base(res) { } autoscope_void(autoscope_void&& move) : base(std::forward<autoscope_void>(move)) { } autoscope_void(autoscope_void& copy) = delete; void delete_resource() { if (m_res != invalid) { verify(fn_delete(m_res)); m_res = invalid; } } }; template <typename resource, typename functor_delete, resource invalid = (resource)-1> struct autoscope_functor : autoscope<resource, autoscope_functor<resource, functor_delete, invalid>, invalid> { typedef autoscope<resource, autoscope_functor, invalid> base; private: functor_delete m_functor_delete; public: autoscope_functor(functor_delete functor_delete) : autoscope(invalid) , m_functor_delete(functor_delete) { } autoscope_functor(resource res, functor_delete functor_delete) : autoscope(res) , m_functor_delete(functor_delete) { } autoscope_functor(autoscope_functor&& move) : base(std::forward<autoscope_functor>(move)) , m_functor_delete(move.m_functor_delete) { } autoscope_functor(autoscope_functor& copy) = delete; void delete_resource() { if (m_res != invalid) { m_functor_delete(m_res); m_res = invalid; } } };
this needs lot of work.
- the deleter shouldn't stored reference. that's recipe disaster, if fix
make_autoscope
take deleter reference. callmake_autoscope
lambda deleter, , code blows up. - the copy , move operations need fixing. default compiler-generated ones not suitable. class should not copyable, must move constructible (for
make_autoscope
work), , may or may not need move assignable. - the interface can use members,
get()
,reset()
, ,release()
. - i'm not sure there's point in worrying size of thing, can store deleter , resource in compressed pair if want. inlining, if deleter function pointer, , thing gets moved around, compiler may not able inline call. that's nothing new.
Comments
Post a Comment