1

我是 C++ 的新手(来自 C)。我从概念上理解 RAII 应该如何工作,但我无法在其中安装一个简单的套接字连接处理程序。

当前代码:

void accept_ev(event_handler::token &t, int listenfd)
{
    int newfd = accept(listenfd, NULL, NULL);

    if (newfd < 0)
        throw api_server_accept_failed(*this, errno);

    connections.insert(api_server_connection(newfd));
}

这显然是不安全的,因为 api_server_connection 构造函数可能会在将 fd 分配给其成员变量之前引发异常。

所以我的下一个想法是将接受移动到构造函数中。问题是我真的希望 api_server_connection 不知道 fd 的来源。例如,如果我想在将来支持 inetd,它也可以像 fd 0 一样传递到程序中。

那么我该怎么做。我应该为每种获取 fd 的方式使用不同的构造函数吗?我应该做子类吗?另一种选择可能是有一个 lambda 函数?

或者在这种情况下我应该抓住任何错误并关闭调用者中的 fd 吗?

4

2 回答 2

4

暂时忽略套接字,您通常想要做的是将事情分为两个阶段。

在第一阶段,您会做一些可能会抛出的事情,但如果他们这样做了,您可以将系统恢复到正常状态(最好是好像什么都没发生过的状态)。

在第二阶段,你做一些你可能无法撤消,但你知道肯定永远不会扔掉的事情。

为此,您需要对可以/将要抛出的内容有一些保证,并且(特别是)对至少一些根本不会抛出的相当具体的操作(例如,交换两个项目)有一些保证。

为了促进这一点,您通常希望在 dtor 中恢复到正常状态,因此如果抛出异常,析构函数将自动清理。

不幸的是,很难说更多关于您的特定代码/情况的信息,因为我们对您正在使用的类知之甚少。

于 2012-04-26T20:00:37.820 回答
0

首先,为了使用 RAII,您必须以面向对象的方式进行思考。所以我看到您尝试使用 C++ 实现服务器类。在这种情况下,您将仅将 RAII 用于服务器初始化,这意味着您将编写代码并在服务器开始侦听端口时完成它。构造函数中的最后一个函数调用必须是监听或启动连接线程。之后,您必须实现将处理客户端连接的第二个线程。第二个线程将调用 accept 以接受客户端,并将在服务器工作时进行迭代。在您的析构函数中,您只需将侦听标志设置为 false 并等待接受线程终止,然后关闭所有套接字。

于 2012-04-26T19:40:43.867 回答