I have written this program that has a main function, inside which, I am creating two sockets, like this:
int sockfd1 = socket(AF_INET, SOCK_STREAM, 0);
int sockfd2 = socket(AF_INET, SOCK_STREAM, 0);
Now I do some stuff with them, and when the user presses Ctrl+C to terminate the process, I want to make sure the sockets close properly, so I do this:
auto sigTermHandler = [&] (int param) { close(sockfd1); close(sockfd2); };
signal(SIGTERM, sigTermHandler);
But this throws the following compilation error when compiled as 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)’
Is it not possible to use lambda this way to handle signals? Please advise.
P.S. I know I could put that in a destructor, if I did proper OOP, but I am curious to see if this works.
You cannot use the capture feature from lambda when calling a simple function pointer. The standard states that a lambda function without a capture is convertible to a function pointer, though:
5.1.2 (6) The closure type for a lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function having the same parameter and return types as the closure type’s function call operator. The value returned by this conversion function shall be the address of a function that, when invoked, has the same effect as invoking the closure type’s function call operator.
For instance, this works:
signal(SIGTERM, [](int signum) { /* ... */ });
But not this:
signal(SIGTERM, [foo](int signum) { /* use foo here */ });
You could actually keep sockfd1
and sockfd2
as global variables and then, you could use them in the lambda function. But that is clearly not a good design. So it is better to use a RAII design. And if the program is terminated the sockets will be closed anyway (as @Dani is pointing out).
A little late but if someone needs such a solution one can use std::function
as a wrapper to hold a lambda capable of capturing variables:
#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();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With