24

私はmain関数を持つこのプログラムを作成しました。その中で、次のように2つのソケットを作成しています。

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を実行すれば、それをデストラクタに入れることができることはわかっていますが、これが機能するかどうかを知りたいと思います。

4

3 に答える 3

27

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

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

たとえば、これは機能します:

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

しかし、これではありません:

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

実際に と グローバル変数として保持sockfd1sockfd2、ラムダ関数で使用できます。しかし、それは明らかに良い設計ではありません。そのため、 RAII設計を使用することをお勧めします。そして、プログラムが終了すると、とにかくソケットは閉じられます(@Daniが指摘しているように)。

于 2012-07-13T10:15:36.460 に答える
25

少し遅れましたが、誰かがそのようなソリューションを必要とする場合は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();
}
于 2018-01-09T08:39:04.883 に答える
0

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

于 2012-07-13T10:18:58.920 に答える