7

我是一名尝试学习 C++11 的 C# 开发人员。我正在尝试使用 windns.h 查询 DNS。

我开始DnsQuery()阅读并阅读我需要使用DnsRecordListFree(). C# 方法可能是使用try-finally块来确保无论如何我都释放资源。

但我了解到,没有finally障碍,windns.h 确实应该与时俱进并实现符合 RAII 的接口(正如我理解的典型建议)。我没有等待这种情况发生,而是尝试创建一个 RAII 包装类,其析构函数调用DnsRecordListFree()并使用运算符重载强制转换来获取原始指针。

但我对如何正确使用此句柄或指针来获取 out 参数感到困惑。在我研究的同时,我了解到unique_ptr我已经了解了一点的如何与自定义删除器一起使用。

所以这是我到目前为止的简单代码。可能还有比这更多的错误,但我想我可以声明另一个PDNS_RECORD *presult并将其用作 out 参数,然后复制或移动或以其他方式将其值分配给 a 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;
}

谢谢!

4

2 回答 2

5

你可以花一整天的时间尝试适应标准的智能指针,或者你可以自己写。它们并不难做到,特别是如果您愿意作弊并允许访问原始指针本身。

struct DnsRAII
{
    PDNS_RECORD p;

    DnsRAII() : p(NULL) { }
    ~DnsRAII() { if (p != NULL) DnsRecordListFree(p, DnsFreeRecordList); }
};

DnsRAII results;
if (DnsQuery(L"google.com", DNS_TYPE_A, DNS_QUERY_STANDARD, NULL, &results.p, NULL))
// ...
于 2014-03-12T20:38:29.403 回答
2

Unless I'm missing something (I haven't a Windows box handy to compile this, so forgive me if I am) your code is incorrect. Personally i wouldn't do this with a smart pointer, since all you're essentially using it for is a custom janitor class (and you could write one of those easy-enough).

Regardless, first, your deleter should be :

auto pdnsDeleter = [&](PDNS_RECORD ptr){ if (ptr) DnsRecordListFree(ptr, DnsFreeRecordList); };

Next, the type of your smart pointer should be:

std::unique_ptr<DNS_RECORD, decltype(pdnsDeleter)> results;

Finally, I believe your loadup of this smart pointer should be after determination the function succeeded:

PDNS_RECORD pdnsrec;
if (DnsQuery(L"google.com", DNS_TYPE_A, DNS_QUERY_STANDARD, NULL, &pdnsrec, NULL))
{
    results.reset(pdnsrec);
}

If I got that right, your deleter will be fired correctly on scope exit on the fetched chain. But again, this seems an awful lot of work for what you can effectively make simpler with your own janitor class.

于 2014-03-12T20:42:13.567 回答