我有一个自动作用域类型的想法,当它们离开作用域或者包含对象被破坏时将清理资源。
这就是目前的情况:
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);
}
我看到/遇到的一些潜在/实际问题。
对于每个处理的资源,都会创建一个DELETOR对象或指针。我不确定优化器是否会破坏它并且只是内联DELETOR仿函数或函数指针,以便autoscope对象不会大于RESOURCE句柄。我不确定编译器是否被允许,但我不认为可以将DELETOR 作为一种类型传递给。
我尝试传递HICON
和函数指针DestroyIcon()
,然后崩溃了。调试时显示传递给make_autoscope()
的指针是0x755225e0 {user32.dll!_DestroyCursor@4}
,这显然是错误的。这是VC ++问题(2013)吗?或者还有其他错误吗?
我目前在VS2013中使用VC ++,但这应该是可移植的。
好的,我已经根据评论想出了一些想法。这是我到目前为止所提出的:
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;
}
}
};
答案 0 :(得分:2)
这需要做很多工作。
make_autoscope
也通过引用获取删除,这也是灾难的处方。用lambda作为删除器调用make_autoscope
,你的代码就会爆炸。make_autoscope
可以工作),并且可能需要也可能不需要移动可分配。get()
,reset()
和release()
。答案 1 :(得分:2)
c ++ 11已经拥有unique_ptr<T, Deleter>
和shared_ptr<T>(T*, Deleter())
所需的内容。
没有任何理由在这里重新发明轮子。
例如:
#include <iostream>
#include <cstdio>
#include <memory>
auto main() -> int
{
auto file_closer = [](FILE* fp) -> int
{
return std::fclose(fp);
};
// a unique_ptr who's custom deleter matches the signature of int fclose()
using unique_auto_file = std::unique_ptr<FILE, int (*)(FILE*)>;
unique_auto_file f(fopen("temp.txt", "r"), file_closer);
// a shared_ptr to FILE
using shared_auto_file = std::shared_ptr<FILE>;
// construct with custom deleter (int-ignored)
shared_auto_file fs(fopen("temp.txt", "r"), file_closer);
return 0;
}
注意:由于@ PeterSom的有用评论而更新