2012-07-13 7 views
10

私は、私はこのように、二つのソケットを作成していたの内側に、主な機能を持っているこのプログラムを書かれている:AutoとLambdaを使ってSignalを処理するには?

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

このようにラムダを使用してシグナルを処理することはできませんか?お知らせ下さい。

P.S.私は適切なOOPをしたら、デストラクタにそれを置くことができることを知っていますが、これがうまくいくかどうかを知りたいのです。

答えて

15

単純な関数ポインタを呼び出すときは、ラムダのキャプチャ機能を使用することはできません。標準は、キャプチャのないラムダ関数が関数ポインタに変換可能であると述べている。

5.1.2(6)ラムダキャプチャを使用しないラムダ式のクロージャタイプは、パブリックな非仮想非明示的なconst クロージャ型の 関数呼び出し演算子と同じパラメータと戻り値の型を持つ関数へのポインタへの変換関数。この変換関数によって返される値は、呼び出されるとクロージャ型の関数呼び出し演算子を呼び出すのと同じ効果を持つ関数 のアドレスとする。あなたがラムダでそれらを使用することができ、その後、

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

あなたが実際にsockfd1とグローバル変数としてsockfd2を保つことができると:

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

しかし、これではない:

例えば、これは動作します関数。しかし、それは明らかに良いデザインではありません。したがって、RAIIデザインを使用する方が良いです。そして、プログラムが終了すると、ソケットは(@Daniが指摘しているように)とにかく閉じます。

0

ソケットは、プログラムが閉じられても閉じられますので、心配する必要はありません。
あなたは論理リソースの取り扱いについて心配場合は、デストラクタでそれを置くが、それらのユーザーが押したときに呼び出されませんCTRL-C

1

少し遅れて誰かが1のラッパーとして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(); 
} 
関連する問題