С++ 11 std::bind работает странно

Это менеджер событий, принцип работы которого показан в main(). Итак, код:

class CEventManager
{
public:
    static CEventManager *const GetInstance()
    {
        static CEventManager pInstance;
        return &pInstance;
    };

    template <typename... ARGS>
    bool RegCallback(E_EVSYS_MSG const &_eType, void (*_Func)(ARGS...))
    {
        m_Callbacks[_eType].push_back(_Func);

        return true;
    };

    template <typename... ARGS>
    bool CallEvent(E_EVSYS_MSG const &_eType, ARGS... _Args)
    {
        auto const &FuncsVector = m_Callbacks[_eType];

        for (auto const _Func : FuncsVector)
        {
            typedef void(*FUNC)(ARGS...);
            FUNC StoredFunc = (FUNC)_Func;

            std::function<void()> *pBindFunc = new std::function<void()>;
            *pBindFunc = std::bind(StoredFunc, _Args...);

            m_Queue.push(pBindFunc);
        }

        return true;
    };

    bool Exec()
    {
        while (!m_Queue.empty())
        {
            std::function<void()> *iFunc = new std::function<void()>;
            *iFunc = *m_Queue.back();

            (*iFunc)();

            m_Queue.pop();
        }

        return true;
    };
private:
    std::unordered_map<E_EVSYS_MSG, std::vector<void *>>        m_Callbacks;
    std::queue<std::function<void()> *>             m_Queue;
};

void SomeCallback(int n, float f)
{
    printf("void SomeCallback(int, float): %d %0.1f\n", n, f);
}

int main()
{
    CEventManager::GetInstance()->RegCallback(E_EVSYS_MSG::MATHSQRT, &SomeCallback);

    CEventManager::GetInstance()->CallEvent(E_EVSYS_MSG::MATHSQRT, 10, 10600.0f);
    CEventManager::GetInstance()->CallEvent(E_EVSYS_MSG::MATHSQRT, 12, 1.0f);

    CEventManager::GetInstance()->Exec();
    return 0;
}

И вывод:

void SomeCallback(int, float): 12 1.0

void SomeCallback(int, float): 12 1.0


Если я поменяю местами строки:

CEventManager::GetInstance()->CallEvent(E_EVSYS_MSG::MATHSQRT, 12, 1.0f);
CEventManager::GetInstance()->CallEvent(E_EVSYS_MSG::MATHSQRT, 10, 10600.0f);

Вывод стал таким:

void SomeCallback(int, float): 10 10600.0

void SomeCallback(int, float): 10 10600.0


Отладчик показывает, что в m_Queue все данные верны.

Это означает, что данные в очереди такие:

сначала: func: void(int,float); параметры: 12, 1.0f;

второй: func: void(int,float); параметры: 10, 10600.0f;


Что случилось? Где ошибка?

P.S. Я делаю new std::function<void()>; только для того, чтобы попытаться устранить ошибку...

Visual Studio 2013 (12.0.30..)


person Aleksey    schedule 15.03.2014    source источник
comment
какой компилятор/версия?   -  person pyCthon    schedule 15.03.2014


Ответы (1)


Вы вызываете m_Queue.back() в Exec вместо m_Queue.front():

bool Exec()
{
    while (!m_Queue.empty())
    {
        std::function<void()> *iFunc = new std::function<void()>;
        *iFunc = *m_Queue.back();

        (*iFunc)();

        m_Queue.pop();
    }

    return true;
}

что приводит к вызову второй сохраненной функции дважды и первой сохраненной функции ноль раз.

person Casey    schedule 15.03.2014