【发布时间】:2014-03-12 20:13:58
【问题描述】:
我是一名尝试学习 C++11 的 C# 开发人员。我正在尝试使用 windns.h 查询 DNS。
我从DnsQuery() 开始,读到我需要使用DnsRecordListFree() 释放结果记录输出参数。 C# 方法可能是使用try-finally 块来确保无论如何我都释放资源。
但我了解到没有 finally 块,windns.h 确实应该与时俱进并实现符合 RAII 的接口(据我了解典型建议)。我没有等待这种情况发生,而是尝试创建一个 RAII 包装类,其析构函数调用 DnsRecordListFree() 并使用运算符重载强制转换来获取原始指针。
但我对如何正确使用此句柄或指针来获取输出参数感到困惑。在我研究的同时,我了解到unique_ptr(我已经了解了一点)如何与自定义删除器一起使用。
到目前为止,这是我的简单代码。可能还有比这更多的错误,但我想我可以声明另一个 PDNS_RECORD *presult 并将其用作 out 参数,然后复制或移动或以其他方式将其值分配给 unique_ptr,但这听起来工作量太大/混乱。
在我看来,unique_ptr 的内部指针应该初始化为NULL,我应该能够以某种方式将指针的地址传递给 out 参数,DNSQuery 将更新原始值,并且当unique_ptr 超出我的函数范围时,DnsRecordListFree() 调用将自动进行。我不知道要找出正确/安全使用最少的正确组合。
#include <iostream>
#include <fstream>
#include <memory>
#include <Windows.h>
#include <WinDNS.h>
using namespace std;
auto pdnsDeleter = [&](PDNS_RECORD *ptr){ if (ptr) DnsRecordListFree(ptr); };
int main(int argc, char **argv)
{
cout << "Hello World\n";
std::unique_ptr<PDNS_RECORD*, decltype(pdnsDeleter)> results(0, pdnsDeleter);
if (DnsQuery(L"google.com", DNS_TYPE_A, DNS_QUERY_STANDARD, NULL, ??results??, NULL))
{
cout << "google.com -> " << ??results??;
}
cout << "Done\n";
getchar();
return 0;
}
谢谢!
【问题讨论】:
-
Microsoft API 通常被编写为与 C 兼容而不是 C++,因此它们没有 RAII。包装是要走的路。
-
@MarkRansom 我不确定我是否理解你。您在 RAII 和“包装”之间有什么区别? RAII 是“包装”资源以控制其生命周期和销毁的模式或实践,不是吗?
-
@IronSavior 通过“包装”我的意思是将本机类型放在另一个包装类中。就像你说的那样。
-
@IronSavior 在您所描述的上下文中使用时,Mark 正在讨论它通常称为 janitor 类的内容,清理并在出门时关掉灯门。与成熟的库智能指针相比,它们的构思要简单得多,后者提供了许多其他功能,包括复制保护、共享和引用计数等。
标签: c++ winapi dynamic-memory-allocation out-parameters