3

別のプログラミング言語で使用しましたが、非常に便利です。

C++の場合、これについて何も見つかりません。

たとえば、次のコードを見てみましょう。

void change();

enum
{
    end = 0,
    gmx
}

int
    gExitType;

int main()
{
    gExitType = end;
    SetTimer(&change, 10000, 0);
    return 0;
}

void ApplicationExit()
{
    switch (gExitType)
    {
        case end:
            printf("This application was ended by the server");
        case gmx:
            printf("This application was ended by the timer");
    }
    ::exit(0);
}

void change()
{
    gExitType = gmx;
    ApplicationExit();
}

これは C++ で行う方法のようなものですが、ステート マシン/オートマトンを使用する場合は、他の言語で次のようなことができます。

void change();

int main()
{
    state exitType:end;
    SetTimer(&change, 10000, 0);
    return 0;
}

void ApplicationExit() <exitType:end>
{
    printf("This application was ended by the server");
}

void ApplicationExit() <exitType:gmx>
{
    printf("This application ended by the timer");
}

void change()
{
    state exitType:gmx;
    ApplicationExit();
}

私の意見では、これは物事を達成するための本当にエレガントな方法です。C ++でこれを行うにはどうすればよいですか? このコードは機能していないようです (明らかに、C++ に関連するオートマトンが見つからないためです)。

私の意見を明確にするために:

では、この手法を使用する利点は何ですか? 明らかなように、コードは小さくなっています。確かに、例をより似たものにするために最初のバージョンに列挙型を追加しましたが、ApplicationExit 関数は間違いなく小さくなっています。また、より明示的です。何が起こっているかを判断するために、関数に大きな switch ステートメントは必要ありません。必要に応じて、さまざまなファイルにさまざまな ApplicationExits を配置して、さまざまなコード セットを個別に処理できます。また、使用するグローバル変数も少なくなります。

4

3 に答える 3

3

エンコーディング ステート マシンの豊富なサポートを特に提供しようとする Boost.statechart のような C++ ライブラリがあり
ます。

これに加えて、特定のタイプのステート マシンをエンコードする非常に洗練された方法の 1 つは、それらをクルーチンとして定義すること
です
。 /状態マシンの代替としての共同ルーチン/

コルーチンは C++ では直接サポートされていませんが、それらを実装するには 2 つの方法があります。

1) ダフのデバイスを実装するのと同様の手法を使用して、ここで詳しく説明します :
http://blog.think-async.com/search/label/coroutines
コルーチンからの生成は、コルーチン呼び出しスタックの最上位の関数からのみ実行できます。OTOH、この方法の利点は、コルーチンの各インスタンスに必要なメモリがほとんどないことです。

2) コルーチンごとに個別のスタックとレジスタ空間を割り当てます。
これにより、基本的にコルーチンは本格的な実行スレッドになりますが、唯一の違いは、ユーザーがスレッド スケジューリング (協調的マルチタスキングとも呼ばれます) に対して全責任を負うことです。
移植可能な実装は、boost から入手できます:
http://www.boost.org/doc/libs/1_54_0/libs/coroutine/doc/html/coroutine/intro.html

于 2013-07-08T14:52:52.260 に答える
2

この特定の例では、オブジェクトとポリモーフィズムを使用してさまざまな状態を表すことができます。例えば:

class StateObject
{
    public:
        virtual void action(void) = 0;
};

class EndedBy : public StateObject
{
    private:
        const char *const reason;

    public:
        EndedBy( const char *const reason_ ) : reason( reason_ ) { }
        virtual void action(void)
        {
            puts(reason);
        }
};

EndedBy EndedByServer("This application was ended by the server");
EndedBy EndedByTimer ("This application ended by the timer");

StateObject *state = &EndedByServer;

void change()
{
    state = &EndedByTimer;
}

void ApplicationExit()
{
    state->action();
    ::exit(0);
}

int main()
{
    SetTimer(&change, 10000, 0);

    // whatever stuff here... 
    // presumably eventually causes ApplicationExit() to get called before return 0;

    return 0;
}

とはいえ、これは優れた設計ではなく、一般的な意味での FSM ではありません。しかし、それはあなたの差し迫った必要性を実現します。

このパターンのより一般的な扱いについては 、状態パターン (1 つの参照: http://en.wikipedia.org/wiki/State_pattern ) を調べることができます。

ただし、基本的な考え方は、各状態は共通の「状態」クラスのサブクラスであり、ポリモーフィズムを使用して、各状態によって表されるさまざまなアクションと動作を決定できるということです。共通の「状態」基本クラスへのポインターは、現在の状態を追跡します。

状態オブジェクトは異なるタイプであるか、上記の例のように、異なる構成の同じオブジェクトの異なるインスタンス、またはブレンドである可能性があります。

于 2013-07-06T19:16:37.167 に答える