2012-07-13 49 views
10

我写了这个程序,有一个主要功能,在其内部,我创建了两个插槽,这样的:使用Auto和Lambda来处理信号?

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)’ 

用这种方法来处理信号不可能使用lambda吗?请指教。

P.S.我知道我可以把它放在析构函数中,如果我做了适当的OOP,但我很好奇,看看它是否有效。

回答

15

调用简单函数指针时,不能使用lambda中的捕获功能。该标准状态,如果没有捕获lambda函数可转化为一个函数指针,虽然:

5.1.2(6),用于与无λ-捕获的λ-表达的闭合类型有一个公共非虚非显式const 转换函数指向具有与闭包类型的 函数调用运算符相同的参数和返回类型的函数。此转换函数返回的值应为函数 的地址,该函数在调用时具有与调用闭包类型的函数调用操作符相同的效果。

举例来说,这个工程:

signal(SIGTERM, [](int signum) { /* ... */ }); 

但不是这样的:

signal(SIGTERM, [foo](int signum) { /* use foo here */ }); 

其实你可以保持sockfd1sockfd2为全局变量,然后,你可以在lambda使用它们功能。但这显然不是一个好设计。所以最好使用RAII设计。如果程序终止,套接字将被关闭(正如@Dani指出的那样)。

0

程序关闭时,套接字将始终关闭,无需担心。
如果担心逻辑资源处理,把它放在析构函数,但这些不会被调用,当用户按Ctrl-C

1

晚了一点,但如果有人需要这样的解决方案可以使用std::function作为包装举行能够捕捉变量的lambda:

#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(); 
}