2012-07-13 13 views
10

Napisałem ten program, który ma główną funkcję, wewnątrz którego, tworzę dwa gniazda, tak:Używanie Auto i Lambda do obsługi Signal?

int sockfd1 = socket(AF_INET, SOCK_STREAM, 0); 
int sockfd2 = socket(AF_INET, SOCK_STREAM, 0); 

teraz zrobić kilka rzeczy z nimi, a gdy użytkownik naciśnie Ctrl + C, aby zakończyć proces, chcę się upewnić gniazda zamyka się prawidłowo, więc to zrobić:

auto sigTermHandler = [&] (int param) { close(sockfd1); close(sockfd2); }; 
signal(SIGTERM, sigTermHandler); 

Ale to wyrzuca następujący błąd kompilacji, gdy skompilowany jako 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)’ 

Czy w ten sposób nie można używać sygnałów lambda do obsługi sygnałów? Proszę doradź.

P.S. Wiem, że mógłbym umieścić to w destruktorze, jeśli zrobiłem odpowiedni OOP, ale jestem ciekawy, czy to działa.

Odpowiedz

15

Nie można użyć funkcji przechwytywania z lambda podczas wywoływania prostego wskaźnika funkcji. Standardowe stwierdza, że ​​funkcja lambda bez przechwytywania jest zamienny do wskaźnika funkcji, choć:

5.1.2 (6) Rodzaj zamknięcia dla lambda wyrażenia bez lambda-wychwytywania ma publicznego non-virtual niejawna const funkcja konwersji do wskaźnika dla funkcji o tym samym parametrze i typach zwracanych, co operator wywołania funkcji typu zamknięcia . Wartością zwracaną przez tę funkcję konwersji jest adres funkcji , która po wywołaniu ma taki sam skutek jak wywołanie operatora wywołania funkcji typu zamknięcia.

Na przykład to działa:

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

Ale nie to:

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

Ty faktycznie mogła zachować sockfd1 i sockfd2 jako zmienne globalne, a następnie można je wykorzystywać w lambda funkcjonować. Ale to zdecydowanie nie jest dobry projekt. Więc lepiej jest użyć projektu RAII. A jeśli program zostanie zakończony, gniazda będą i tak zamknięte (jak wskazuje @Dani).

0

Gniazda będą zawsze zamknięte, gdy program zostanie zamknięty, nie trzeba się tym martwić.
Jeśli martwisz się o obsługę zasobów logicznych, umieścić go w destruktorów, ale ci nie zostanie wywołana, gdy użytkownik naciśnie CTRL-C

1

Trochę późno, ale jeśli ktoś potrzebuje takiego rozwiązania można wykorzystać std::function jako owijki aby zachować lambdę zdolną do przechwytywania zmiennych:

#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(); 
} 
Powiązane problemy