C&C++   发布时间:2022-04-03  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了在C中是否存在一种惯用的方法来防止运行一系列操作导致集合发生变异的情况?大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
假设你有一个包含某种可调用对象集合的类foo. foo有一个成员函数run(),它遍历集合并调用每个函数对象. foo还有一个成员remove(…),它将从集合中删除一个调用对象.

是否有一个惯用的,RAII风格的后卫,你可以放入foo.run()和foo.remove(…),以便通过调用foo.run()驱动删除
将被推迟到守卫的破坏者开火?它可以用标准库中的东西来完成吗?这个模式有名字吗?

我目前的代码似乎不够优雅,所以我正在寻找最佳实践类型的解决方案.

注意:这不是关于并发性的.非线程安全的解决方案很好.问题在于重新引入和自我引用.

这是一个问题的例子,没有优雅的“延迟删除”警卫.

class ActionPlayer
{
private:
    std::vector<std::pair<int,std::function<void()>>> actions_;
public:
    void addAction(int id,const std::function<void()>& action)
    {
        actions_.push_back({ id,action });
    }

    void removeAction(int id)
    {
        actions_.erase(
            std::remove_if(
                actions_.begin(),actions_.end(),[id](auto& p) { return p.first == id; }
            ),actions_.end()
        );
    }

    void run()
    {
        for (auto& item : actions_) {
            item.second();
        }
    }
};

其他地方:

...

ActionPlayer player;

player.addAction(1,[]() {
    std::cout << "Hello there" << std::endl;
});

player.addAction(42,[&player]() {
    std::cout << "foobar" << std::endl;
    player.removeAction(1);
});

player.run(); // boom

编辑…好吧,这是我通过RAII锁定对象看到的方式.假设递归最终终止(如果不是用户错误),以下应该处理在运行中运行的抛出和重入调用的操作.我使用了缓存的std :: functions,因为在这代码的实际版本中,addAction和removeAction的等价物是模板函数,它们只能存储在一个vanilla homogeneously类型的容器中.

class ActionPlayer
{
private:

    std::vector<std::pair<int,std::function<void()>>> actions_;
    int run_lock_count_;
    std::vector<std::function<void()>> deferred_ops_;

    class RunLock
    {
    private:
        ActionPlayer* parent_;
    public:
        RunLock(ActionPlayer* parent) : parent_(parent) { (parent_->run_lock_count_)++; }
        ~RunLock()
        {
            if (--parent_->run_lock_count_ == 0) {
                while (!parent_->deferred_ops_.empty()) {
                    auto do_deferred_op = parent_->deferred_ops_.back();
                    parent_->deferred_ops_.pop_back();
                    do_deferred_op();
                }
            }
        }
    };

    bool isFiring() const
    {
        return run_lock_count_ > 0;
    }

public:
    ActionPlayer() : run_lock_count_(0)
    {
    }

    void addAction(int id,const std::function<void()>& action)
    {
        if (!isFiring()) {
            actions_.push_back({ id,action });
        } else {
            deferred_ops_.push_back(
                [&]() {
                    addAction(id,action);
                }
            );
        }
    }

    void removeAction(int id)
    {
        if (!isFiring()) {
            actions_.erase(
                std::remove_if(
                    actions_.begin(),[id](auto& p) { return p.first == id; }
                ),actions_.end()
            );
        } else {
            deferred_ops_.push_back(
                [&]() {
                    removeAction(id); 
                }
            );
        }
    }

    void run()
    {
        RunLock lock(this);
        for (auto& item : actions_) {
            item.second();
        }
    }
};

解决方法

通常的方法是创建矢量的副本.但这可能会导致删除的操作再次运行.
void run()
{
    auto actions_copy{actions_};
    for (auto& item : actions_copy) {
        item.second();
    }
}

不允许运行已删除操作的其他选项

>如果删除某些操作,则添加bool以存储>使用shared / weak ptr>如果已知当前操作不会被删除,请使用std :: list.

大佬总结

以上是大佬教程为你收集整理的在C中是否存在一种惯用的方法来防止运行一系列操作导致集合发生变异的情况?全部内容,希望文章能够帮你解决在C中是否存在一种惯用的方法来防止运行一系列操作导致集合发生变异的情况?所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。
标签: