To realize the raii idiom for the type SOCKET
, I have created a wrapper. The wrapper calls connect
in the constructor and closesocket
in its destructor. A std::map
holds all used sockets. Unfortunatelly inserting a new socket into the container calls the destructor of a temporary and, in fact, closes the just opened socket. Is there a common way to overcome this?
Here is the code:
#include <iostream>
#include <stdexcept>
#include <map>
#include <winsock2.h>
struct Socket {
SOCKET mSock;
Socket() : mSock(INVALID_SOCKET) {}
Socket(std::string ip, int port);
~Socket();
};
Socket::Socket(std::string ip, int port) {
mSock = socket(AF_INET, SOCK_STREAM, 0);
if (mSock == INVALID_SOCKET)
throw std::runtime_error("socket()");
SOCKADDR_IN addr = {0};
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(ip.c_str());
if (connect(mSock, reinterpret_cast<SOCKADDR*>(&addr), sizeof(addr))
== SOCKET_ERROR)
throw std::runtime_error("connect()");
std::cout << mSock << " connected" << std::endl;
}
Socket::~Socket() {
if (mSock != INVALID_SOCKET) {
closesocket(mSock);
std::cout << mSock << " closed" << std::endl;
}
}
int main() {
WSADATA wsa;
WSAStartup(MAKEWORD(2, 0), &wsa);
std::map<int, Socket> outbound;
// calls constructur but also destructor
outbound[0] = Socket("192.168.128.125", 4023);
WSACleanup();
return 0;
}
And the Output is:
1952 connected
1952 closed
1952 closed
Resource guards may be stored in STL containers if you wrap them in a smart pointer. Which smart pointer to use exactly is up to your environment, I'd recommend to go with boost::shared_ptr as a starting point if you're not sure.
Following that way you will conform with both resource guard semantics (only one instance that manages resource's lifetime) and STL container (keep equivalent copy of passed item).