最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++實(shí)現(xiàn)狀態(tài)機(jī)的四種方法

 更新時(shí)間:2026年06月02日 09:21:32   作者:筠筠喵嗚喵  
本文主要介紹了狀態(tài)機(jī)實(shí)現(xiàn)的四種方法,包括Switch、stdstd::variant&std::visit、查表法和狀態(tài)模式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

1.Switch

  • 優(yōu)點(diǎn):直觀、零額外抽象、性能最好
  • 缺點(diǎn):case 越多越臃腫,邏輯分散。
#include <iostream>

enum class State { Idle, Running, Paused, Error };
enum class Event { Start, Pause, Resume, Stop, ErrorOccur, Reset };

struct SM {
    State s = State::Idle;
    void dispatch(Event ev) {
        switch (s) {
            case State::Idle:
                if (ev == Event::Start) { enter(State::Running); }
                else if (ev == Event::ErrorOccur) { enter(State::Error); }
                break;
            case State::Running:
                if (ev == Event::Pause) { enter(State::Paused); }
                else if (ev == Event::Stop) { enter(State::Idle); }
                else if (ev == Event::ErrorOccur) { enter(State::Error); }
                break;
            case State::Paused:
                if (ev == Event::Resume) { enter(State::Running); }
                else if (ev == Event::Stop) { enter(State::Idle); }
                else if (ev == Event::ErrorOccur) { enter(State::Error); }
                break;
            case State::Error:
                if (ev == Event::Reset) { enter(State::Idle); }
                break;
        }
    }
    void enter(State ns) {
        onExit(s);
        s = ns;
        onEnter(s);
    }
    void onEnter(State st) {
        std::cout << "enter " << toString(st) << "\n";
    }
    void onExit(State st) {
        std::cout << "exit " << toString(st) << "\n";
    }
    static const char* toString(State st) {
        switch (st) {
            case State::Idle: return "Idle";
            case State::Running: return "Running";
            case State::Paused: return "Paused";
            case State::Error: return "Error";
        }
        return "Unknown";
    }
};

int main() {
    SM sm;
    sm.dispatch(Event::Start);
    sm.dispatch(Event::Pause);
    sm.dispatch(Event::Resume);
    sm.dispatch(Event::ErrorOccur);
    sm.dispatch(Event::Reset);
    return 0;
}

2. std::variant + std::visit

  • 優(yōu)點(diǎn):每個(gè)狀態(tài)行為封裝成類型,類型安全且可內(nèi)聯(lián)(無虛調(diào)用)。
  • 缺點(diǎn):增加類型數(shù)量,添加新狀態(tài)需改 variant 列表和工廠。
#include <iostream>
#include <variant>
#include <memory>

struct Context;

// 各狀態(tài)類型封裝行為
struct Idle {
    static void onEnter(Context&);
    static void onExit(Context&);
    static void handle(Context&, int ev);
    static constexpr const char* name = "Idle";
};
struct Running {
    static void onEnter(Context&);
    static void onExit(Context&);
    static void handle(Context&, int ev);
    static constexpr const char* name = "Running";
};
struct Paused {
    static void onEnter(Context&);
    static void onExit(Context&);
    static void handle(Context&, int ev);
    static constexpr const char* name = "Paused";
};
struct ErrorSt {
    static void onEnter(Context&);
    static void onExit(Context&);
    static void handle(Context&, int ev);
    static constexpr const char* name = "Error";
};

using StateVar = std::variant<Idle, Running, Paused, ErrorSt>;

struct Context {
    StateVar state{Idle{}};
    void dispatch(int ev) {
        std::visit([&](auto &st){
            using T = std::decay_t<decltype(st)>;
            T::handle(*this, ev);
        }, state);
    }
    void setState(StateVar ns) {
        std::visit([&](auto &st){ using T = std::decay_t<decltype(st)>; T::onExit(*this); }, state);
        state = std::move(ns);
        std::visit([&](auto &st){ using T = std::decay_t<decltype(st)>; T::onEnter(*this); }, state);
    }
    void log(const char* msg) { std::cout << msg << "\n"; }
};

void Idle::onEnter(Context& c){ c.log("enter Idle"); }
void Idle::onExit(Context& c){ c.log("exit Idle"); }
void Idle::handle(Context& c, int ev){
    if(ev==1) c.setState(Running{});
    else if(ev==99) c.setState(ErrorSt{});
    else c.log("Idle ignore");
}

void Running::onEnter(Context& c){ c.log("enter Running"); }
void Running::onExit(Context& c){ c.log("exit Running"); }
void Running::handle(Context& c, int ev){
    if(ev==2) c.setState(Paused{});
    else if(ev==0) c.setState(Idle{});
    else if(ev==99) c.setState(ErrorSt{});
    else c.log("Running ignore");
}

void Paused::onEnter(Context& c){ c.log("enter Paused"); }
void Paused::onExit(Context& c){ c.log("exit Paused"); }
void Paused::handle(Context& c, int ev){
    if(ev==3) c.setState(Running{});
    else if(ev==0) c.setState(Idle{});
    else if(ev==99) c.setState(ErrorSt{});
    else c.log("Paused ignore");
}

void ErrorSt::onEnter(Context& c){ c.log("enter Error"); }
void ErrorSt::onExit(Context& c){ c.log("exit Error"); }
void ErrorSt::handle(Context& c, int ev){
    if(ev==4) c.setState(Idle{});
    else c.log("Error ignore");
}

int main(){
    Context ctx;
    ctx.dispatch(1);   // Start -> Running
    ctx.dispatch(2);   // Pause -> Paused
    ctx.dispatch(3);   // Resume -> Running
    ctx.dispatch(99);  // Error -> Error
    ctx.dispatch(4);   // Reset -> Idle
    return 0;
}

3.查表法

  • 優(yōu)點(diǎn):配置化、數(shù)據(jù)驅(qū)動、容易以表格/文件維護(hù)和測試,性能極高。
  • 缺點(diǎn):運(yùn)行時(shí)查表開銷、復(fù)雜行為(guards/enter/exit)仍需回調(diào)。動作(action)與狀態(tài)分離,擴(kuò)展性較差
#include <iostream>
#include <map>
#include <functional>
#include <tuple>

enum class State { Idle, Running, Paused, Error };
enum class Event { Start, Pause, Resume, Stop, ErrorOccur, Reset };

// 表項(xiàng):(State,Event) -> (new State, action)
using Key = std::pair<State, Event>;
struct Action { State next; std::function<void()> act; };

struct SM {
    std::map<Key, Action> table;
    State s = State::Idle;
    SM() {
        table[{State::Idle, Event::Start}] = {State::Running, [this](){ log("Idle->Running"); }};
        table[{State::Idle, Event::ErrorOccur}] = {State::Error, [this](){ log("Idle->Error"); }};
        table[{State::Running, Event::Pause}] = {State::Paused, [this](){ log("Running->Paused"); }};
        table[{State::Running, Event::Stop}] = {State::Idle, [this](){ log("Running->Idle"); }};
        table[{State::Running, Event::ErrorOccur}] = {State::Error, [this](){ log("Running->Error"); }};
        table[{State::Paused, Event::Resume}] = {State::Running, [this](){ log("Paused->Running"); }};
        table[{State::Paused, Event::Stop}] = {State::Idle, [this](){ log("Paused->Idle"); }};
        table[{State::Paused, Event::ErrorOccur}] = {State::Error, [this](){ log("Paused->Error"); }};
        table[{State::Error, Event::Reset}] = {State::Idle, [this](){ log("Error->Idle"); }};
    }

    void dispatch(Event ev) {
        auto it = table.find({s, ev});
        if (it != table.end()) {
            onExit(s);
            it->second.act();
            s = it->second.next;
            onEnter(s);
        } else {
            log("no transition");
        }
    }

    void onEnter(State st){ std::cout << "enter " << name(st) << "\n"; }
    void onExit(State st){ std::cout << "exit " << name(st) << "\n"; }
    void log(const char* m){ std::cout << m << "\n"; }
    static const char* name(State st){
        switch(st){ case State::Idle: return "Idle"; case State::Running: return "Running"; case State::Paused: return "Paused"; case State::Error: return "Error"; }
        return "Unknown";
    }
};

int main(){
    SM sm;
    sm.dispatch(Event::Start);
    sm.dispatch(Event::Pause);
    sm.dispatch(Event::Resume);
    sm.dispatch(Event::ErrorOccur);
    sm.dispatch(Event::Reset);
    return 0;
}

4.狀態(tài)模式(虛函數(shù)實(shí)現(xiàn))

  • 優(yōu)點(diǎn):面向?qū)ο?、可在狀態(tài)間封裝復(fù)雜 enter/exit 行為,運(yùn)行時(shí)靈活。
  • 缺點(diǎn):類數(shù)量與抽象開銷(虛函數(shù)/堆分配),需謹(jǐn)慎優(yōu)化(對象復(fù)用或單例狀態(tài)可減開銷)。
#include <iostream>
#include <memory>
#include <string>

enum class Event { Start, Pause, Resume, Stop, ErrorOccur, Reset };

class Context;
struct State {
    virtual ~State() = default;
    virtual void onEnter(Context&) {}
    virtual void onExit(Context&) {}
    virtual void handle(Context&, Event) = 0;
    virtual std::string name() const = 0;
};

class Context {
public:
    void setState(std::unique_ptr<State> s) {
        if (state) state->onExit(*this);
        state = std::move(s);
        if (state) state->onEnter(*this);
    }
    void handle(Event ev) {
        if (state) state->handle(*this, ev);
    }
    void log(const std::string &m) { std::cout << m << "\n"; }
private:
    std::unique_ptr<State> state;
};

// Concrete states
struct Idle : State {
    void onEnter(Context& c) override { c.log("enter Idle"); }
    void onExit(Context& c) override { c.log("exit Idle"); }
    void handle(Context& c, Event ev) override;
    std::string name() const override { return "Idle"; }
};
struct Running : State {
    void onEnter(Context& c) override { c.log("enter Running"); }
    void onExit(Context& c) override { c.log("exit Running"); }
    void handle(Context& c, Event ev) override;
    std::string name() const override { return "Running"; }
};
struct Paused : State {
    void onEnter(Context& c) override { c.log("enter Paused"); }
    void onExit(Context& c) override { c.log("exit Paused"); }
    void handle(Context& c, Event ev) override;
    std::string name() const override { return "Paused"; }
};
struct ErrorState : State {
    void onEnter(Context& c) override { c.log("enter Error"); }
    void onExit(Context& c) override { c.log("exit Error"); }
    void handle(Context& c, Event ev) override;
    std::string name() const override { return "Error"; }
};

void Idle::handle(Context& c, Event ev){
    if(ev==Event::Start) c.setState(std::make_unique<Running>());
    else if(ev==Event::ErrorOccur) c.setState(std::make_unique<ErrorState>());
    else c.log("Idle ignore");
}
void Running::handle(Context& c, Event ev){
    if(ev==Event::Pause) c.setState(std::make_unique<Paused>());
    else if(ev==Event::Stop) c.setState(std::make_unique<Idle>());
    else if(ev==Event::ErrorOccur) c.setState(std::make_unique<ErrorState>());
    else c.log("Running ignore");
}
void Paused::handle(Context& c, Event ev){
    if(ev==Event::Resume) c.setState(std::make_unique<Running>());
    else if(ev==Event::Stop) c.setState(std::make_unique<Idle>());
    else if(ev==Event::ErrorOccur) c.setState(std::make_unique<ErrorState>());
    else c.log("Paused ignore");
}
void ErrorState::handle(Context& c, Event ev){
    if(ev==Event::Reset) c.setState(std::make_unique<Idle>());
    else c.log("Error ignore");
}

int main(){
    Context ctx;
    ctx.setState(std::make_unique<Idle>());
    ctx.handle(Event::Start);
    ctx.handle(Event::Pause);
    ctx.handle(Event::Resume);
    ctx.handle(Event::ErrorOccur);
    ctx.handle(Event::Reset);
    return 0;
}

5. 方案對比總結(jié)

方案優(yōu)點(diǎn)缺點(diǎn)適用場景
switch1. 最簡單直觀
2. 零額外抽象,性能最好(編譯期確定)
3. 代碼集中,便于理解
1. 狀態(tài)/事件增多時(shí),switch-case 臃腫
2. 邏輯分散,可維護(hù)性差
3. 難以擴(kuò)展(添加新狀態(tài)需修改多處)
狀態(tài)機(jī)規(guī)模?。?lt;10 個(gè)狀態(tài)),性能要求極高,且不預(yù)期頻繁變更的場景
std::variant + std::visit1. 類型安全,每個(gè)狀態(tài)行為封裝為獨(dú)立類型
2. 無虛函數(shù)調(diào)用,可內(nèi)聯(lián)優(yōu)化
3. 編譯期檢查,避免遺漏狀態(tài)處理
1. 類型數(shù)量增加,代碼量較大
2. 添加新狀態(tài)需修改 variant 列表和工廠
3. 對 C++17 及以上版本有要求
狀態(tài)集固定,希望將行為與類型綁定,且追求高性能、類型安全的場景
查表法1. 高度配置化、數(shù)據(jù)驅(qū)動
2. 易于維護(hù)和測試(表格/文件可外部化)
3. 性能極高(O(1) 查表)
4. 狀態(tài)轉(zhuǎn)換邏輯集中
1. 運(yùn)行時(shí)查表有輕微開銷
2. 復(fù)雜行為(guard 條件、enter/exit)仍需回調(diào)函數(shù)
3. 動作與狀態(tài)分離,擴(kuò)展性較差
狀態(tài)轉(zhuǎn)換規(guī)則穩(wěn)定、希望外部配置、便于測試和動態(tài)調(diào)整的場景
狀態(tài)模式(虛函數(shù))1. 面向?qū)ο?,符合開閉原則
2. 易于管理復(fù)雜的 enter/exit 行為
3. 運(yùn)行時(shí)靈活,狀態(tài)可動態(tài)替換
4. 結(jié)構(gòu)清晰,職責(zé)分離
1. 虛函數(shù)調(diào)用開銷(運(yùn)行時(shí)多態(tài))
2. 類數(shù)量多,可能涉及堆分配
3. 若狀態(tài)對象非單例,會有對象創(chuàng)建開銷
狀態(tài)行為復(fù)雜、需要封裝大量狀態(tài)專屬邏輯、且預(yù)期會頻繁擴(kuò)展的場景

到此這篇關(guān)于C++實(shí)現(xiàn)狀態(tài)機(jī)的四種方法的文章就介紹到這了,更多相關(guān)C++ 狀態(tài)機(jī)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++浮點(diǎn)型的存儲方式詳解

    C++浮點(diǎn)型的存儲方式詳解

    本篇文章是對C/C++浮點(diǎn)數(shù)在內(nèi)存中的存儲方式進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下,希望能夠給你帶來幫助
    2021-09-09
  • C語言實(shí)例講解四大循環(huán)語句的使用

    C語言實(shí)例講解四大循環(huán)語句的使用

    C語言有四大循環(huán)語句,他們之間可以進(jìn)行任意轉(zhuǎn)換。本文將首先對其語法進(jìn)行講解,然后通過一個(gè)實(shí)例用四種循環(huán)來實(shí)現(xiàn)。相信通過本文的學(xué)習(xí),大家都能夠?qū)語言循環(huán)語句有著熟練的掌握
    2022-05-05
  • 解決scanf_s輸入%d%c%d格式錯誤的問題

    解決scanf_s輸入%d%c%d格式錯誤的問題

    這篇文章主要介紹了解決scanf_s輸入%d%c%d格式錯誤的問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • sdl顯示一張bmp圖片示例

    sdl顯示一張bmp圖片示例

    這篇文章主要介紹了sdl顯示一張bmp圖片示例,需要的朋友可以參考下
    2014-04-04
  • 淺析C語言中printf(),sprintf(),scanf(),sscanf()的用法和區(qū)別

    淺析C語言中printf(),sprintf(),scanf(),sscanf()的用法和區(qū)別

    以下是對C語言中printf(),sprintf(),scanf(),sscanf()的用法以及區(qū)別進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以參考下
    2013-07-07
  • C++中vector迭代器失效問題的原因及解決方案

    C++中vector迭代器失效問題的原因及解決方案

    迭代器(iterator)是一種用于遍歷數(shù)據(jù)集合的的對象,它提供了一種訪問數(shù)據(jù)集合中元素的方式,而無需暴露數(shù)據(jù)集合內(nèi)部的細(xì)節(jié),使用迭代器,我們可以對數(shù)據(jù)集合中的每個(gè)元素進(jìn)行處理,本文介紹了C++中關(guān)于vector迭代器失效問題的原因及解決方案,需要的朋友可以參考下
    2024-09-09
  • C++中this指針的介紹及使用實(shí)例講解

    C++中this指針的介紹及使用實(shí)例講解

    這篇文章主要介紹了C++中this指針的介紹及使用實(shí)例講解,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2025-05-05
  • C++使用string的大數(shù)取模運(yùn)算(5)

    C++使用string的大數(shù)取模運(yùn)算(5)

    這篇文章主要為大家詳細(xì)介紹了C++使用string的大數(shù)取模運(yùn)算,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-09-09
  • C語言詳解關(guān)鍵字sizeof與unsigned及signed的用法

    C語言詳解關(guān)鍵字sizeof與unsigned及signed的用法

    這篇文章主要為大家詳細(xì)介紹了C語言關(guān)鍵字sizeof&&unsigned&&signed,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • C++利用libcurl獲取下載文件名稱及大小

    C++利用libcurl獲取下載文件名稱及大小

    這篇文章主要為大家詳細(xì)介紹了C++如何利用libcurl獲取下載文件名稱及大小的功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2023-03-03

最新評論

厦门市| 泰州市| 伊川县| 灵璧县| 大丰市| 左云县| 望奎县| 广宁县| 临沧市| 霞浦县| 南召县| 会同县| 若尔盖县| 镇赉县| 弥渡县| 都江堰市| 邓州市| 株洲市| 衡阳市| 石台县| 大宁县| 西宁市| 马山县| 兴山县| 武陟县| 根河市| 兰州市| 蚌埠市| 白银市| 汕头市| 酉阳| 大新县| 高淳县| 亚东县| 晴隆县| 彭水| 宁阳县| 武功县| 桃江县| 天柱县| 哈巴河县|