我写了这个程序,有一个主要功能,在其内部,我创建了两个插槽,这样的:
int sockfd1 = socket(AF_INET, SOCK_STREAM, 0);
int sockfd2 = socket(AF_INET, SOCK_STREAM, 0);
现在我做一些东西与他们,当用户按下CTRL + C来终止这个过程中,我想确保插座正常关闭,所以我这样做:
auto sigTermHandler = [&] (int param) { close(sockfd1); close(sockfd2); };
signal(SIGTERM, sigTermHandler);
但是,当如本编译引发以下编译错误g++ -std=gnu++0x <filename>.cpp
:
error: cannot convert ‘main(int, char**)::<lambda(int)>’ to ‘__sighandler_t {aka void (*)(int)}’ for argument ‘2’ to ‘void (* signal(int, __sighandler_t))(int)’
这难道不是可以使用拉姆达这种方式来处理信号? 请指教。
PS我知道我可以把在析构函数,如果我做了正确的OOP,但我很好奇,看看这是否正常工作。
调用一个简单的函数指针时,不能从拉姆达使用捕捉功能。 该标准规定,如果没有捕获lambda函数可以转换为一个函数指针,但:
5.1.2(6)的闭合类型没有λ-捕获的λ-表达具有一个公共非虚拟非显式const的转换函数的指针的作用具有相同的参数和返回类型为闭合类型的函数调用操作。 通过这种转换函数的返回值应是一个函数调用时,与调用闭合类型的函数调用操作的效果相同的地址。
举例来说,这个工程:
signal(SIGTERM, [](int signum) { /* ... */ });
但不是这样的:
signal(SIGTERM, [foo](int signum) { /* use foo here */ });
其实你可以保持sockfd1
和sockfd2
为全局变量,然后,你可以在lambda函数中使用它们。 但是,这显然不是一个好的设计。 因此,最好是使用RAII设计。 如果程序终止插座无论如何都会被关闭(如@Dani指向了)。
晚了一点,但如果有人需要这样的解决方案可以使用std::function
作为包装来保存能够捕获变量的拉姆达:
#include <functional>
#include <iostream>
namespace {
std::function<void(int)> shutdown_handler;
void signal_handler(int signal) { shutdown_handler(signal); }
} // namespace
int main(int argc, char *argv[]) {
std::signal(SIGINT, signal_handler);
MyTCPServer server;
shutdown_handler = [&](int signal) {
std::cout << "Server shutdown...\n";
server.shutdown();
};
server.do_work_for_ever();
}
套接字将永远被关闭时,一个程序关闭,没有必要担心。
如果担心的逻辑资源处理,把它放在析构函数,但这些不会被调用当用户按下CTRL-C