Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Smart pointers with addrinfo struct

I need to deal with two struct addrinfo pointers. Since I'm coding in C++(11), I've to make my code exception-safe. Indeed, my costructors may throw a runtime_error. When you don't need that kind of struct anymore, you should call freeaddrinfo in order to free the list inside the struct. Please consider the following code:

#include <memory>
#include <netdb.h>

class SomeOtherClass
{
  public:
    SomeOtherClass() : hints(new addrinfo), result(new addrinfo) { /*stuff*/ }
    ~SomeOtherClass() { freeaddrinfo(result.get()); } // bad things will happen

private:
    std::unique_ptr<addrinfo> hints, result;
};

class MyClass : public SomeOtherClass
{
public:
    MyClass() { /* hints initialization, call to getaddrinfo, etc. */ }

private:
    // ...
};

My questions are:

  1. addrinfo is an "old" C structure, with no ctor/dtor to call: is it safe to use new?
  2. getaddrinfo requires a pointer to a pointer to a addrinfo struct: how should I pass it via smart pointers?
  3. What about calling freeaddrinfo? It's considered unsafe to delete (or better free) the pointer that the smart pointer is holding.

For hints there is no problem, since its lifetime is smaller.

like image 522
edmz Avatar asked Feb 21 '14 18:02

edmz


2 Answers

For any addrinfo you allocate yourself, it is safe to use newand delete, so you can use the default implementation of unique_ptr to handle that.

For any addrinfo that getaddrinfo() allocates, you must use freeaddrinfo() to free it. You can still use unique_ptr for that, but you must specify freeaddrinfo() as a custom Deleter, eg:

class SomeOtherClass
{
  public:
    SomeOtherClass() : hints(new addrinfo), result(nullptr, &freeaddrinfo) { /*stuff*/ }

private:
    std::unique_ptr<addrinfo> hints;
    std::unique_ptr<addrinfo, void(__stdcall*)(addrinfo*)> result;
};

Then you can do this:

getaddrinfo(..., &result);

Or this, if std::unique_ptr does not override the & operator:

addrinfo *temp;
getaddrinfo(..., &temp);
result.reset(temp);

UPDATE: a better option is to use decltype and let the compiler deduce the function type of the Deleter for you:

std::unique_ptr<addrinfo, decltype(&freeaddrinfo)> result;
like image 122
Remy Lebeau Avatar answered Sep 20 '22 06:09

Remy Lebeau


In addition to other answers: C++23 introduces a new feature for smart pointers interacting with C-style output parameters. Now, instead of replacing the managed object with a temporary value, we can use std::out_ptr():

getaddrinfo(..., std::out_ptr(result));
like image 34
Doliman100 Avatar answered Sep 21 '22 06:09

Doliman100