C++ 如何检查;“类型”;运行时Win32句柄的
我必须在C++11中为Win32句柄(如HFONT、HWND、HMODULE等)编写一个引用计数包装类。我想使用一个WinHandle类隐式地强制转换到所有句柄类型(都是void*typedef)。不幸的是,所有句柄都有不同的函数来销毁底层对象,例如DestroyWindow()、CloseHandle()、DeleteObject()等等,因此我需要为每个句柄类型使用不同的类来实现相应的销毁函数。(这将是47个类+基类,包括用户对象、gdi对象和内核对象) 那么,有没有一种方法可以在运行时确定句柄是哪种类型的,或者更确切地说,需要调用哪种函数?(在文档中,我只找到了isWindow()函数)C++ 如何检查;“类型”;运行时Win32句柄的,c++,winapi,c++11,C++,Winapi,C++11,我必须在C++11中为Win32句柄(如HFONT、HWND、HMODULE等)编写一个引用计数包装类。我想使用一个WinHandle类隐式地强制转换到所有句柄类型(都是void*typedef)。不幸的是,所有句柄都有不同的函数来销毁底层对象,例如DestroyWindow()、CloseHandle()、DeleteObject()等等,因此我需要为每个句柄类型使用不同的类来实现相应的销毁函数。(这将是47个类+基类,包括用户对象、gdi对象和内核对象) 那么,有没有一种方法可以在运行时确定
我已经考虑过使用RTTI或调用所有delete函数,直到其中一个成功。RTTI不起作用,因为所有句柄类型都是void*的typedef,因此是相同的。后者可能会工作,但所有句柄都必须是唯一的才能正常工作(没有一个GDI句柄可以与用户句柄或内核句柄具有相同的值),否则它可能会导致错误和内存泄漏如果您只需要一个引用计数的句柄,为什么不直接使用
shared\u ptr
例如:
shared\u ptr文件(CreateFile(L“la.txt”、GENERIC\u WRITE、file\u shared\u READ、NULL、CREATE\u ALWAYS、file\u ATTRIBUTE\u NORMAL、NULL)、CloseHandle);
德沃德写的;
WriteFile(file.get(),//获取句柄
“ABC\r\n”,
5.
&写,,
无效);
它不会在你的代码中留下很大的足迹,你也不必编写40个类
通过为每种类型的关闭定义一些函数,可以避免每次传递相关的关闭函数,例如:
auto make_handle_CloseHandle = [](HANDLE h){ return (shared_ptr<void>(h,CloseHandle)); };
auto file = make_handle_CloseHandle(CreateFile(L"la.txt", /*same ...*/));
DWORD written;
WriteFile( file.get(), //get handle
"ABC\r\n",
5,
&written,
NULL);
auto make_handle_CloseHandle=[](句柄h){return(共享的_ptr(h,CloseHandle));};
auto file=make_handle_CloseHandle(创建文件(L“la.txt”/*相同…*/);
德沃德写的;
WriteFile(file.get(),//获取句柄
“ABC\r\n”,
5.
&写,,
无效);
并将其放在相关名称空间下的某个头文件中,这样您就不必每次都键入close函数的名称,这些函数的用户就会知道调用了哪个函数(根据
make\u handle.*
name)这可能比仅通过句柄自动识别句柄类型更安全。如果您只需要一个引用计数的句柄,为什么不直接使用shared\u ptr
例如:
shared\u ptr文件(CreateFile(L“la.txt”、GENERIC\u WRITE、file\u shared\u READ、NULL、CREATE\u ALWAYS、file\u ATTRIBUTE\u NORMAL、NULL)、CloseHandle);
德沃德写的;
WriteFile(file.get(),//获取句柄
“ABC\r\n”,
5.
&写,,
无效);
它不会在你的代码中留下很大的足迹,你也不必编写40个类
通过为每种类型的关闭定义一些函数,可以避免每次传递相关的关闭函数,例如:
auto make_handle_CloseHandle = [](HANDLE h){ return (shared_ptr<void>(h,CloseHandle)); };
auto file = make_handle_CloseHandle(CreateFile(L"la.txt", /*same ...*/));
DWORD written;
WriteFile( file.get(), //get handle
"ABC\r\n",
5,
&written,
NULL);
auto make_handle_CloseHandle=[](句柄h){return(共享的_ptr(h,CloseHandle));};
auto file=make_handle_CloseHandle(创建文件(L“la.txt”/*相同…*/);
德沃德写的;
WriteFile(file.get(),//获取句柄
“ABC\r\n”,
5.
&写,,
无效);
并将其放在相关名称空间下的某个头文件中,这样您就不必每次都键入close函数的名称,这些函数的用户就会知道调用了哪个函数(根据
make\u handle.*
name)这可能比仅仅通过句柄自动识别句柄类型更安全。因为CreateFile的失败结果是无效的句柄值(-1),我不确定这是一个好的解决方案
与其使用一些旨在引用内存地址的内容,不如实现某种共享的_资源或唯一的_资源类型,它接受模板参数或封装包装类型特征的单个参数
我的看起来像这样:
template <typename TRAITS>
struct SharedHandle
{
....
}
struct TestTraits
{
using HandleType = int;
static constexpr HandleType INVALID = 0;
static void Close(HandleType& h)
{
h = INVALID;
}
};
using SharedHandleTestType = SharedHandle<TestTraits>;
TEST(ClvLib_SharedHandle_Tests, SharedHandle_default)
{
auto tt = SharedHandleTestType();
EXPECT_FALSE(tt);
}
TEST(ClvLib_SharedHandle_Tests, SharedHandle_good)
{
auto tt = SharedHandleTestType(1);
EXPECT_TRUE(tt);
}
TEST(ClvLib_SharedHandle_Tests, SharedHandle_use)
{
auto tt = SharedHandleTestType(1);
auto result = [](int t)->int {return t + 1; }(tt);
auto expected = tt.Get() + 1;
EXPECT_EQ(expected, result);
}
TEST(ClvLib_SharedHandle_Tests, SharedHandle_copy1)
{
auto tt = SharedHandleTestType(1);
auto t2 = tt;
EXPECT_TRUE(tt);
EXPECT_TRUE(t2);
tt = 0;
EXPECT_FALSE(tt);
EXPECT_TRUE(t2);
}
TEST(ClvLib_SharedHandle_Tests, SharedHandle_copy2)
{
auto tt = SharedHandleTestType(1);
auto t2 = tt;
EXPECT_TRUE(tt);
EXPECT_TRUE(t2);
tt = 0;
EXPECT_FALSE(tt);
EXPECT_TRUE(t2);
t2.Release();
EXPECT_FALSE(tt);
EXPECT_FALSE(t2);
}
模板
结构SharedHandle
{
....
}
它的用法如下:
template <typename TRAITS>
struct SharedHandle
{
....
}
struct TestTraits
{
using HandleType = int;
static constexpr HandleType INVALID = 0;
static void Close(HandleType& h)
{
h = INVALID;
}
};
using SharedHandleTestType = SharedHandle<TestTraits>;
TEST(ClvLib_SharedHandle_Tests, SharedHandle_default)
{
auto tt = SharedHandleTestType();
EXPECT_FALSE(tt);
}
TEST(ClvLib_SharedHandle_Tests, SharedHandle_good)
{
auto tt = SharedHandleTestType(1);
EXPECT_TRUE(tt);
}
TEST(ClvLib_SharedHandle_Tests, SharedHandle_use)
{
auto tt = SharedHandleTestType(1);
auto result = [](int t)->int {return t + 1; }(tt);
auto expected = tt.Get() + 1;
EXPECT_EQ(expected, result);
}
TEST(ClvLib_SharedHandle_Tests, SharedHandle_copy1)
{
auto tt = SharedHandleTestType(1);
auto t2 = tt;
EXPECT_TRUE(tt);
EXPECT_TRUE(t2);
tt = 0;
EXPECT_FALSE(tt);
EXPECT_TRUE(t2);
}
TEST(ClvLib_SharedHandle_Tests, SharedHandle_copy2)
{
auto tt = SharedHandleTestType(1);
auto t2 = tt;
EXPECT_TRUE(tt);
EXPECT_TRUE(t2);
tt = 0;
EXPECT_FALSE(tt);
EXPECT_TRUE(t2);
t2.Release();
EXPECT_FALSE(tt);
EXPECT_FALSE(t2);
}
struct TestTraits
{
使用HandleType=int;
静态constexpr HandleType无效=0;
静态空隙闭合(手柄类型和h)
{
h=无效;
}
};
使用SharedHandleteType=SharedHandle;
测试(ClvLib_SharedHandle_测试,SharedHandle_默认)
{
auto tt=SharedHandleteType();
预期错误(tt);
}
测试(ClvLib_SharedHandle_测试,SharedHandle_良好)
{
自动tt=SharedHandleteType(1);
期望真实(tt);
}
测试(ClvLib_SharedHandle_测试,SharedHandle_使用)
{
自动tt=SharedHandleteType(1);
自动结果=[](int t)->int{返回t+1;}(tt);
自动预期=tt.Get()+1;
期望值(期望值、结果);
}
测试(ClvLib_SharedHandle_测试,SharedHandle_copy1)
{
自动tt=SharedHandleteType(1);
自动t2=tt;
期望真实(tt);
期望值为真(t2);
tt=0;
预期错误(tt);
期望值为真(t2);
}
测试(ClvLib_SharedHandle_测试,SharedHandle_副本2)
{
自动tt=SharedHandleteType(1);
自动t2=tt;
期望真实(tt);
期望值为真(t2);
tt=0;
预期错误(tt);
期望值为真(t2);
t2.释放();
预期错误(tt);
期望值为假(t2);
}
对于Windows文件句柄:
struct WinHandleTraits_IHV
{
using HandleType = HANDLE;
static constexpr HandleType INVALID = INVALID_HANDLE_VALUE;
static void Close(HandleType& h)
{
CloseHandle(h);
}
};
using WinFileHandle = SharedHandle<WinHandleTraits_IHV>;
struct WinHandleTraits\u IHV
{
使用HandleType=HANDLE;
static constexpr HandleType INVALID=无效的句柄值;
静态空隙闭合(手柄类型和h)
{
闭合手柄(h);
}
};
使用WinFileHandle=SharedHandle;
由于CreateFile的失败结果是无效的\u HANDLE\u值(-1),因此我不确定这是一个好的解决方案
实现一些