我是c ++的新手,学习如何做到最好的方法。 我在绘画方面看到了很多有用的例子,但我没有看到任何简单的疙瘩getdc和智能课程。
所以我写了自己的一个:
class DCObject
{
public:
DCObject(HWND handle)
{
my_handle = handle;
my_hdc = GetDC(my_handle);
}
HDC GetHDC() {
return my_hdc;
}
~DCObject()
{
ReleaseDC(my_handle, my_hdc);
}
private:
HWND my_handle;
HDC my_hdc;
};
我试图像这样得到hdc:
HDC mydc = DCObject(dialog_item_handle).GetHDC();
这是对的吗?要asq for class方法,首先不要创建类对象?在这种情况下,课程会发生什么?也许我确实得到了hdc并且它立即被释放了?(它可以工作,但它可能会产生未定义的行为与hdc' s)
也许我应该这样做:
DCObject myhdcobj(dialog_item_handle);
HDC mydc = myhdcobj.GetHDC();
答案 0 :(得分:1)
我就是这样做的。
#include <iostream>
#include <memory>
#include <windows.h>
template<typename T, typename D = void(*)(T &val)>
struct gdi_type
{
typedef typename std::remove_reference<typename std::remove_pointer<T>::type>::type type;
typedef typename std::unique_ptr<typename gdi_type<T>::type, D> unique_ptr_type;
};
template<typename T>
auto safe_gdi(const T &val)
{
return typename gdi_type<T>::unique_ptr_type(val, [](T &t) {DeleteObject(t);});
}
auto safe_gdi(const HDC &val)
{
return gdi_type<HDC>::unique_ptr_type(val, [](HDC &t) {DeleteDC(t);});
}
auto safe_gdi(const HWND &win, const HDC &val)
{
auto deleter = [=](HDC &val) {ReleaseDC(win, val); val = nullptr;};
return gdi_type<HDC, decltype(deleter)>::unique_ptr_type(val, deleter);
}
int main()
{
HWND win = GetDesktopWindow();
HDC DC = safe_gdi(win, GetDC(win)).get();
HDC CDC = safe_gdi(CreateCompatibleDC(DC)).get();
HPEN PEN = safe_gdi(CreatePen(PS_DASH, 0, 0xFF)).get();
return 0;
}
答案 1 :(得分:0)
如果您没有将DCObject(dialog_item_handle)
分配给变量,最终会得到Temporary Object。
创建它们的表达式完成后,将销毁临时对象。在您的情况下,在分配到mydc
之后。因此,在分配mydc
之后,将调用临时对象的析构函数,并释放DC。不是你想要的。
第二个版本可行。你的myhdcobj
只有在超出范围时才被销毁 - 也就是说,当你离开这个功能时。
答案 2 :(得分:0)
声明
HDC mydc = DCObject(dialog_item_handle).GetHDC();
调用DCObject
构造函数,创建一个临时对象。在完整表达式结束时(保证)销毁临时对象。因此,在此语句之后,临时对象已被销毁,并且析构函数已调用ReleaseDC
...
解决方案:存储对象而不是句柄
const DCObject mydc( dialog_item_handle );
我更愿意将其写为
auto const mydc = DCObject( dialog_item_handle );
...但问题中提到的DCObject
类是不安全,因为没有处理复制/移动所以临时对象的析构函数在右边,将致电ReleaseDC
...
要为常量声明启用更自然的auto
表示法,并且通常启用移动和禁用复制,请执行以下操作:
class DCObject
{
private:
HWND my_handle;
HDC my_hdc;
DCObject( DCObject const& ) = delete;
DCObject& operator=( DCObject const& ) = delete;
public:
auto handle() const -> HDC { return my_hdc; }
~DCObject()
{ ReleaseDC( my_handle, my_hdc ); }
DCObject( const HWND handle )
: my_handle( handle )
, my_hdc( GetDC( handle ) )
{}
DCObject( DCObject&& other )
: my_handle( other.my_handle )
, my_hdc( other.my_hdc )
{ other.my_hdc = 0; }
};
其他类型句柄的代码 - 即使是其他使用的设备上下文句柄 - 将非常相似。
表达作为通用类模板的一个主要见解是清理所需的附加状态,例如:这里的窗口句柄可以是指定的清理函数或类函数对象的一部分,特别是作为lambda中的捕获。
如果你还没有使用lambdas那么请记住这一点。
您也可以在不使用lambdas的情况下使用有状态删除原则。