-1

Updated

Will this line of code work:

boost::shared_array<struct sockaddr> addr(
    reinterpret_cast<struct sockaddr *>(
        (ipv6 ? new unsigned char [sizeof(struct sockaddr_in6)]
              : new unsigned char [sizeof(struct sockaddr_in)])
    )
);

Note the two different data types between allocation and the type given in the <template>.


The original question was with boost::shared_ptr

Will this line of code work:

boost::shared_ptr<struct sockaddr> addr(
    reinterpret_cast<struct sockaddr *>(
        (ipv6 ? new unsigned char [sizeof(struct sockaddr_in6)]
              : new unsigned char [sizeof(struct sockaddr_in)])
    )
);

Note the two different data types between allocation and the type given in the <template>.

Solution

boost::shared_array<unsigned char> address(new unsigned char [sizeof(sockaddr_in)]);

NOTE: The same type of unsigned char is being used with a size exactly of the one that's needed.

and then when I am going to use it:

bind(, (sockaddr*)address.get(), );
unixman83
  • 9,421
  • 10
  • 68
  • 102
  • No. See http://stackoverflow.com/questions/4255598/delete-vs-delete – tauran Dec 28 '11 at 11:41
  • Just run it and see what happens. – Casey Robinson Dec 28 '11 at 11:43
  • @CaseyRobinson: It's not always possible to see undefined behaviour. – Mike Seymour Dec 28 '11 at 11:45
  • You probably got downvoted because you didn't present much of your own research effort, or more detailed explanations like your ideas on the topic, just a snippet of code (or because people don't like undefined behaviour in C++ :-)). Your question is a valid question though, so don't worry. – Kos Dec 28 '11 at 11:50
  • 1
    @BoPersson The manpages for `bind()` tell you to explictly do just that, cast a `sockaddr_in6 *` to `sockaddr *`. – unixman83 Dec 28 '11 at 11:53

3 Answers3

6

This is incorrect. At one point the smart pointer would try to do something like:

sockaddr* data;
// ...
delete data; // boom!

Your buffer needs to be deleted another way (with delete[] not delete and through a pointer of a correct type).

Have a look at boost::shared_array, maybe that's what you actually need.


After your edits and the comments

A type-safe solution would be to use:

typedef boost::shared_ptr<
     boost::variant<sockaddr_in,
                    sockaddr_in6>
     > sharedSockaddr;

// helper function for interaction with C
sockaddr* getSockaddr(sharedSockaddr addr) {

    struct printer : boost::static_visitor<>
    {
       sockaddr* out;

       void operator()(const sockaddr_in& t)
       {
          out = reinterpret_cast<sockaddr*>(&t);
       }

       void operator()(const sockaddr_in6& t)
       {
          out = reinterpret_cast<sockaddr*>(&t);
       }
    };

    printer p;
    boost::apply_visitor(p, *addr);
    return p.out;
}

Use sharedSockaddrs within your code and use getSockaddr whenever you need to obtain a sockaddr* to pass to the C API.

Kos
  • 70,399
  • 25
  • 169
  • 233
  • `boost::shared_array` is exactly what I was looking for, will the type in the template differing from the `unsigned char []` matter? – unixman83 Dec 28 '11 at 11:44
  • You should assume that it does matter. Why aren't you trying to be type-safe here and doing those strange casts, anyway? – Kos Dec 28 '11 at 11:46
  • I cannot pass a `boost::variant` to C code (Linux BSD sockets API). – unixman83 Dec 28 '11 at 11:49
  • 1
    You can't pass a `shared_pointer` too. :-) How about: store it as `variant` and just `reinterpret_cast` it to `sockaddr*` as late as possible to keep *your* code clean and safe. – Kos Dec 28 '11 at 11:53
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/6188/discussion-between-unixman83-and-kos) – unixman83 Dec 28 '11 at 11:56
  • What is "as late as possible" ? When receiving `sockaddr`s from `recvfrom()` or `accept()`, "as late as possible" is nearly after the construction. This is what you get when you use object oriented API from C. – BatchyX Dec 28 '11 at 12:00
3

To be on the safe side, you should use a custom deleter to do a reinterpret_cast back to the original pointer type before deleting:

boost::shared_ptr<struct sockaddr> addr(
    reinterpret_cast<struct sockaddr *>(
        (ipv6 ? new unsigned char [sizeof(struct sockaddr_in6)]
              : new unsigned char [sizeof(struct sockaddr_in)])
    ),
    [](struct sockaddr* ptr) {
        delete[] reinterpret_cast<unsigned char*>(ptr);
    }
);

If your compiler does not support lambdas, you can use a regular function instead.

void delete_the_socket(struct sockaddr* ptr) {
    delete[] reinterpret_cast<unsigned char*>(ptr);
}
R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
-1

Why don't you use the operator new() directly?

boost::shared_ptr<struct sockaddr> addr(
    ipv6 ? static_cast<struct sockaddr*>(::operator new(sizeof(struct sockaddr_in6)))
         : static_cast<struct sockaddr*>(::operator new(sizeof(struct sockaddr_in)))
);
Inbae Jeong
  • 4,053
  • 25
  • 38
  • `static_cast` won't work here: `struct sockaddr_in6` and `sockaddr_in` are C structs that are designed to be casted to `struct sockaddr` using C casts, they do not inherit from `struct sockaddr`. Think of this as C-based OO programming. – BatchyX Dec 28 '11 at 18:59
  • @BatchyX That's exactly the reason the operator new is used. The return type of `::operator new()' is void* and static_cast works. The only difference is that the operator new is used instead of malloc(), since the default deleter of shared_ptr frees the memory with 'delete' – Inbae Jeong Dec 28 '11 at 20:02
  • 1
    According to the standard, only pointers obtained from the `new` operator can be passed to the `delete` operator (with exceptions for types with virtual destructors, which C structures do not have). The `::operator new` allocation function is not the same as the `new` operator. – Ben Voigt Dec 30 '11 at 02:07