C ++虚拟方法,不需要"这个"指针 - 优化

时间:2017-07-06 15:45:15

标签: c++ optimization virtual-method

我想实现对某个类的访问:

class A { some properties and methods };

问题是A可以存在多个状态,并且方法需要相应地运行。一种方法是:

class A
{
    void Method1() { 
        if (A is in state 1) { do something }
        else if (A is in state 2) { do something else }
        ...
    }
};

如果方法被多次调用,那显然不是最优的。因此,一个易于实现的解决方案是为不同的状态创建几个类:

class A
{
    class State1 {
        virtual void Method1(A& a) { do something; }
        ...
    } State1Instance;

    class State2 { ... }
    ...
};

然后根据当前状态(例如State1Instance)管理指向对象的指针,并调用此对象的方法。这避免了CPU消耗情况。

但是国家#方法也收到了完全无用的#34;这个"指向State对象的指针。有办法避免这种情况吗?我知道差别很小,但我试图尽可能地使其最佳,并且使用CPU寄存器获得完全无意义的值并不理想。这实际上很适合用于虚拟静态"但是这是禁止的。

3 个答案:

答案 0 :(得分:1)

如果您真的关心重复的分支,请使用好的旧函数指针,通常您不应该这样做。

struct A
{
    using StateFn = void (*)(A&);

    static void State1(A& a) { a.i = 42; }
    static void State2(A& a) { a.i = 420; }

    void Method1() { s(*this); }

    StateFn s = State1;
    int i;
};

如果您有多个与每个州相关联的方法,则可以构建一个方法表

struct A
{
    static void State1M1(A& a) { a.i = 42; }
    static void State2M1(A& a) { a.i = 420; }

    static int State1M2(A& a) { return a.i * 42; }
    static int State2M2(A& a) { return a.i * 420; }

    // The naming sucks, you should find something better

    static constexpr struct {
        void (*Method1)(A&);
        int (*Method2)(A&);
    } State[] = {{State1M1, State1M2}, {State2M1, State2M2}};

    void Method1() { State[s].Method1(*this); }
    int Method2() { return State[s].Method2(*this); }

    int s, i;
};

我很好奇,如果这甚至超过了switch声明,请在采用它之前做基准测试。当你开始像第二种情况那样开始构建一个方法表时,你真的不会以一种相当不优化的方式做一些与多态不同的事情。

答案 1 :(得分:1)

如果您真的想要使用它,请使用自由或静态函数,而不是多态,并使用here封装它们。你甚至可以在这里使用lambdas。

Sub Driver()

    Dim Driver As String

    uiDriver = Application.InputBox("Filter out Driver", Type:=2)
    If uiDriver = "False" Then Exit Sub: Rem Cancel pressed

    Range("A1").Select
    Selection.AutoFilter
    Selection.AutoFilter field:=2, Criteria1:="<>*" & uiDriver & "*", Operator:=xlAnd

End Sub

但是,在大多数情况下,class A { public: ::std::function<void(A*)> state = func1; static void func1(A* that) { ::std::cout << "func1\n"; that->state = func2; } static void func2(A* that) { ::std::cout << "func2\n"; that->state = [](A* that) { ::std::cout << "lambda\n"; that->state = func1; }; } public: void method() { state(this); } }; switch 块会更好,因为它可以由编译器优化,可以将其转换为跳转表。如有疑问,请以此为基准!

答案 2 :(得分:0)

c ++ 17中开箱即用的最通用的解决方案之一,并且提升优先级是variant类型和static_visitor的概念。

使用c ++ 14和boost::variant我创建了一个非常简单的状态机,它使用基于类型的代码路径切换以及自动捕获未计入的状态/事件组合。

对于更全面的解决方案,我会将您推荐给boost fsm仅限头文件库。

#include <boost/variant.hpp>
#include <iostream>
#include <typeinfo>

struct event1 {
};

struct event2 {
};

struct state_machine {

    struct state1 {
    };

    struct state2 {
    };

    struct state3 {
    };

    using state_type = boost::variant<state1, state2, state3>;


    struct handle_event {
        // default case for event/state combinations we have not coded for
        template<class SM, class State, class Event>
        void operator()(SM &sm, State &state, Event const&event) const {
            std::cout << "unhandled event "
                      "state=" << typeid(state).name() << " "
                      "event=" << typeid(event).name() << std::endl;
        }

        template<class SM>
        void operator()(SM &sm, state1 &state, event1 const&event) const {
            std::cout << "received event1 while in state1 - switching to state 2" << std::endl;
            sm.change_state(state2());
        }

        template<class SM>
        void operator()(SM &sm, state2 &state, event2 const&event) const {
            std::cout << "received event2 while in state2 - switching to state 1" << std::endl;
            sm.change_state(state1());
        }

        template<class SM>
        void operator()(SM &sm, state1 &state, event2 const&event) const {
            std::cout << "received event2 while in state1 - switching to state 3" << std::endl;
            sm.change_state(state3());
        }

    };


    template<class Event>
    auto notify_event(Event const&evt) {
        return boost::apply_visitor([this, &evt](auto& state)
                                    {
                                        handle_event()(*this, state, evt);
                                    }, state_);
    }

    template<class NewState>
    void change_state(NewState&& ns) {
        state_ = std::forward<NewState>(ns);
    }


private:

    state_type state_ = state1{};
};

int main()
{
    state_machine sm {};

    sm.notify_event(event1());
    sm.notify_event(event2());
    sm.notify_event(event2());

    // we have not coded for this one
    sm.notify_event(event2());
}

示例输出(确切输出将取决于编译器ABI):

received event1 while in state1 - switching to state 2
received event2 while in state2 - switching to state 1
received event2 while in state1 - switching to state 3
unhandled event state=N13state_machine6state3E event=6event2