2

I'm trying to implement a simple TCP server application using winsock2. To this end I have a class that accepts connections (TcpServer) and a class that handles connections (TcpListener). To this end these objects need to share SOCKET, whis is defined as UINT_PTR. To safely share this a shared_ptr seems to be the way to go. Unfortunately it seems that a shared_ptr should wrap a struct or class, hence my implementation below.

struct SafeSocket_
{
    SOCKET Socket;
    SafeSocket_(SOCKET socket)
        : Socket(socket)
    {}
    ~SafeSocket_()
    {
        closesocket(Socket);
        std::cout << "destroyed SafeSocket_" << std::endl;
    }
};
typedef std::shared_ptr<SafeSocket_> SafeSocket;

To create/accept a new socket I use the following horrible code. What's worse even is that I need to use ClientSocket->Socket all over the place.

SafeSocket ClientSocket = SafeSocket(new SafeSocket_(accept(ListenSocket, NULL, NULL)));

There must be a better way of handling this besides using a nice wrapper library.

Note: I'm aware there are nice wrapper libraries likes asio from boost, but I'm just messing around to get my head around some of the C++ basics.

Wouter
  • 2,170
  • 1
  • 28
  • 58

1 Answers1

1

The basic problem is that UINT_PTR isn't an opaque pointer. It's an integer. If it was typedef struct __socket SOCKET;, then you could just write std::shared_ptr<decltype(*SOCKET{})>, stick in a custom deleter to call close_socket, and you'd be laughing.

There are a number of possible approaches:

  • Make SafeSocket be a class which contains the shared_ptr, and which has a socket member function. Then you write ClientSocket.socket() all over the place.
  • As above, but give SafeSocket versions of the socket functions, and it provides the actual socket argument. So instead of read( ClientSocket.Socket, ...) you write ClientSocket.read(...).
  • Revert to SafeSocketas a typedef, but put the additional functions in SafeSocket_, so you write ClientSocket->read(...)

I think I prefer the middle solution best.

  • Good lord! It's taken three edits to get that nearly right! – Martin Bonner supports Monica Dec 13 '15 at 13:43
  • 2
    It is possible to [have a `SOCKET` in a `std::unique_ptr`](http://stackoverflow.com/questions/24611215/one-liner-for-raii-on-non-pointer) using a custom `Deleter` that defines `SOCKET` as the `pointer` type even though it is not really a pointer. Not sure if the same can be done with `std::shared_ptr`, though it does support a custom `Deleter` as well, but maybe or maybe not custom pointers? I haven't dug into it to look yet. – Remy Lebeau Dec 13 '15 at 17:09
  • I chose the middle solution. What Remy suggests would be nice, but I now realise it would be confusing to wrap a resource number in a pointer container. – Wouter Dec 14 '15 at 09:26