我应该如何使用getDC作为autocleanup的本地对象? C ++

时间:2014-12-22 21:55:03

标签: c++ gdi

我是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();

3 个答案:

答案 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的情况下使用有状态删除原则。