1

私はC ++の初心者です(Cから来ました)。RAII がどのように機能するかは概念的に理解していますが、単純なソケット接続ハンドラを RAII に適合させるのに苦労しています。

現在のコード:

void accept_ev(event_handler::token &t, int listenfd)
{
    int newfd = accept(listenfd, NULL, NULL);

    if (newfd < 0)
        throw api_server_accept_failed(*this, errno);

    connections.insert(api_server_connection(newfd));
}

api_server_connection コンストラクターは fd をそのメンバー変数に割り当てる前に例外を発生させる可能性があるため、これは明らかに安全ではありません。

そこで私の次の考えは、accept をコンストラクターに移動することでした。問題は、fd がどこから来たのかについて api_server_connection を知りたくないということです。たとえば、将来 inetd をサポートしたい場合は、fd 0 としてプログラムに渡すこともできます。

では、どうすればよいのでしょうか。fd を取得する方法ごとに異なるコンストラクターを使用する必要がありますか? おそらくサブクラスを作成する必要がありますか?別のオプションは、ラムダ関数を持つことでしょうか?

または、その場合、エラーをキャッチして呼び出し元の fd を閉じる必要がありますか?

4

2 に答える 2

4

今のところソケットを無視して、あなたが通常やりたいことは物事を2つのフェーズに分割することです。

最初のフェーズでは、スローする可能性のあることを実行しますが、スローする場合は、システムを正常な状態(できれば何も起こらなかったかのような状態)に復元できます。

2番目のフェーズでは、元に戻すことはできないかもしれませんが、確実にスローされないことを知っていることを行います。

そのためには、何をスローできるか、何をスローするかについての保証と、(特に)まったくスローできない特定の操作(2つのアイテムの交換など)についての保証が必要です。

これを容易にするために、通常はdtorで正常な状態に復元する必要があるため、例外がスローされた場合、デストラクタは自動的にクリーンアップします。

残念ながら、使用しているクラスについて十分な知識がないため、特定のコード/状況についてそれ以上のことを言うのは困難です。

于 2012-04-26T20:00:37.820 に答える
0

まず、RAII を使用するには、オブジェクト指向の方法で考える必要があります。c++ を使用してサーバー クラスを実装しようとしているようです。この場合、サーバーの初期化にのみ RAII を使用します。つまり、コードを記述し、サーバーがポートのリッスンを開始するときにコードを終了します。コンストラクターの最後の関数呼び出しは、接続スレッドをリッスンまたは開始する必要があります。その後、クライアント接続を処理する 2 番目のスレッドを実装する必要があります。2 番目のスレッドは、クライアントを受け入れるために accept を呼び出し、サーバーが動作している間反復されます。デストラクタでは、リスニング フラグを false に設定し、受け入れスレッドが終了するのを待ってから、すべてのソケットを閉じるだけです。

于 2012-04-26T19:40:43.867 に答える