Я разработчик C #, пытающийся изучать C ++ 11. Я пытаюсь запросить DNS с помощью windns.h.
Я начал с DnsQuery()
и читать, что мне нужно освободить параметр записи результатов с DnsRecordListFree()
, C # способ может быть использовать try-finally
заблокировать, чтобы я освободил ресурс, несмотря ни на что.
Но я узнал, что нет finally
block и тот windns.h действительно должен идти в ногу со временем и реализовывать интерфейс, совместимый с RAII (как я понимаю, типичный совет). Вместо того чтобы ждать, пока это произойдет, я попытался создать класс-оболочку RAII, чей деструктор вызывает DnsRecordListFree()
и с приведением перегрузки оператора, чтобы получить исходный указатель.
Но я был озадачен тем, как правильно использовать этот дескриптор или указатель для получения параметра out. И пока я исследовал, что я узнал, как unique_ptr
, о котором я уже немного узнал, можно использовать с пользовательским средством удаления.
Итак, вот мой простой код. Там, вероятно, больше, чем просто это неправильно, но я полагаю, я мог бы объявить еще один PDNS_RECORD *presult
и использовать его в качестве параметра out, а затем скопировать или переместить или иным образом назначить его значение в unique_ptr
, но это звучит как слишком много работы / беспорядка.
Мне кажется, что unique_ptr
внутренний указатель должен быть инициализирован NULL
что я должен каким-то образом быть в состоянии передать адрес указателя в выходной параметр, что 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;
}
Спасибо!
Вы можете потратить весь день на адаптацию стандартного интеллектуального указателя или написать свой собственный. Их не сложно сделать, особенно если вы хотите обмануть и разрешить доступ к самому необработанному указателю.
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))
// ...
Если я что-то упустил (у меня нет окна Windows, удобного для компиляции, так что простите, если я), ваш код неверен. Лично я не стал бы делать это с помощью умного указателя, поскольку все, для чего вы по сути его используете, — это собственный класс уборщика (и вы могли бы написать один из этих достаточно простых).
Независимо от того, во-первых, ваш удалитель должен быть:
auto pdnsDeleter = [&](PDNS_RECORD ptr){ if (ptr) DnsRecordListFree(ptr, DnsFreeRecordList); };
Далее тип вашего умного указателя должно быть:
std::unique_ptr<DNS_RECORD, decltype(pdnsDeleter)> results;
Наконец, я верю вашему LoadUp этого умного указателя должно быть после определения, что функция выполнена успешно:
PDNS_RECORD pdnsrec;
if (DnsQuery(L"google.com", DNS_TYPE_A, DNS_QUERY_STANDARD, NULL, &pdnsrec, NULL))
{
results.reset(pdnsrec);
}
Если я правильно понял, ваш удалитель будет корректно сработать при выходе из области в выбранной цепочке. Но опять же, это кажется огромной работой для того, что вы можете эффективно упростить с вашим собственным классом уборщика.