【发布时间】:2013-07-25 17:02:43
【问题描述】:
为了实现SOCKET 类型的raii 习惯用法,我创建了一个包装器。包装器在构造函数中调用connect,在其析构函数中调用closesocket。 std::map 包含所有使用的套接字。不幸的是,将一个新套接字插入容器会调用临时的析构函数,实际上是关闭刚刚打开的套接字。有没有通用的方法来克服这个问题?
代码如下:
#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;
}
输出是:
1952 connected
1952 closed
1952 closed
【问题讨论】:
-
使用移动语义并删除
Socket的复制构造器/赋值。仔细想想,复制一个socket是没有意义的。 -
首先,您必须使其不可复制,尽管它应该是可移动的。
-
@syam:我不能使用移动语义,因为:我尝试将这个 VC6 项目转换为 Visual Studio 2010 项目,但由于依赖于链接的 VC6 库,这是不可能的。跨度>
-
如果实现了
connect方法,我相信您也可以执行outbound[0].connect("192.168.128.125", ...)之类的操作。正如 syam 所说,将复制构造函数/赋值运算符设为私有以防止您注意到的错误。 -
@ChristianAmmer 好的。然后不要存储对象本身,而是对它的指针/引用(正如 Yury 所说,智能指针是一个不错的选择)。尽管如此,do 使您的类不可复制,以便您可以在编译时检测到此类问题。