在C中是否存在一种惯用的方法来防止运行一系列 *** 作导致集合发生变异的情况?

在C中是否存在一种惯用的方法来防止运行一系列 *** 作导致集合发生变异的情况?,第1张

概述假设你有一个包含某种可调用对象集合的类foo. foo有一个成员函数run(),它遍历集合并调用每个函数对象. foo还有一个成员remove(…),它将从集合中删除一个可调用对象. 是否有一个惯用的,RAII风格的后卫,你可以放入foo.run()和foo.remove(…),以便通过调用foo.run()驱动删除  将被推迟到守卫的破坏者开火?它可以用标准库中的东西来完成吗?这个模式有名字吗? 假设你有一个包含某种可调用对象集合的类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中是否存在一种惯用的方法来防止运行一系列 *** 作导致集合发生变异的情况?所遇到的程序开发问题。

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

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1239247.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-06
下一篇 2022-06-06

发表评论

登录后才能评论

评论列表(0条)

保存