c++引用无效

C++ Reference invalidation

本文关键字:无效 引用 c++      更新时间:2023-10-16

我正在为游戏引擎编写一个事件系统,我需要一种从事件中"断开"函数的方法(从std::vector中删除),但我也要求删除事件时开发者必须给出他们希望断开的函数的有效引用。

现在我有一个这样的类:

template<typename ... Args>
class event{
    public:
        using delegate_type = std::function<void(Args...)>;
        void operator()(Args ... args){
            for(auto &&f : m_funcs)
                f(args...);
        }
        template<typename FunctorType>
        delegate_type &connect(FunctorType &&f){
            m_funcs.emplace_back(f);
            return m_funcs.back();
        }
        bool disconnect(delegate_type &f){
            for(auto iter = begin(m_funcs); iter != end(m_funcs); ++iter)
                if(&(*iter) == &f){ // if the dev passed a valid function
                    m_funcs.erase(iter);
                    return true;
                }
            return false;
        }
    private:
        std::vector<delegate_type> m_funcs;
};

但是,当在disconnectconnect操作后调整底层向量的大小时,这当然会受到引用无效的影响。

我尝试切换到std::list解决方案,而不是std::vector,但迭代函数时的速度差异是有害的,我不能在发布构建中切换。

是否有一些方法可以避免使用helper类或标识符而不是直接引用的无效?

我建议你看一下Boost.Signals2。当连接时,它返回一个sigc::connection对象。您可以将其保持在客户端并使用它来断开连接,或者它将在插槽被破坏时自动断开连接。它不会受到引用无效问题的困扰。

存储weak_ptr<delegate_type>。在每次调用时删除无效的(remove_if)。( operator())。以某种方式防止递归调用。

返回shared_ptr<delegate_type>作为令牌。外部用户只需使用.reset()取消注册。无需disconnect !

connect中分配make_shared<delegate_type>

使connect成为template,完美地向前进入make_shared

使用一个关联容器,就像刚才使用的std::list。

但是,您需要更复杂地使用容器,以便消除循环的开销。
最好的解决方案当然是去掉循环。

最有效的方法是返回容器单元格的迭代器,而不是返回函数本身。
这样的移除可以避免搜索,因为你已经有了迭代器的位置。
在关联容器中,迭代器不会失效(但要注意,这当然不是线程安全的)。

template<typename FunctorType>
        std::list<delegate_type>::iterator &connect(FunctorType &&f){
            m_funcs.emplace_back(f);
            //get the iterator for the last item
            return m_funcs.end()--;
        }
bool disconnect(std::list<delegate_type>::iterator &f){
           //direct removal
            m_funcs.erase(f);
            return true;
        }