【问题标题】:How to erase while iterating boost::intrusive::list如何在迭代 boost::intrusive::list 时擦除
【发布时间】:2017-12-20 22:49:55
【问题描述】:

如何在迭代时从boost::intrusive::list 中删除元素?以下代码因断言失败而失败https://wandbox.org/permlink/nzFshFSsaIrvBiTa

#include <iostream>
#include <vector>
#include <boost/intrusive/list.hpp>

using std::cout;
using std::endl;

class Integer : public boost::intrusive::list_base_hook<> {
public:
    explicit Integer(int a_in) : a{a_in} {}
    int a;
};

int main() {
    auto vec = std::vector<Integer>{};
    vec.push_back(Integer{1});
    vec.push_back(Integer{2});
    vec.push_back(Integer{3});
    auto list = boost::intrusive::list<Integer>{};
    for (auto ele : vec) {
        list.push_back(ele);
    }

    for (auto it = list.begin(); it != list.end();) {
        if (it->a == 2) {
            it = list.erase(it);
        } else {
            ++it;
        }
    }

    for (auto ele : list) {
        cout << ele.a << endl;
    }
}

【问题讨论】:

    标签: c++ list boost boost-intrusive


    【解决方案1】:

    您的问题是您已将临时人员推入列表:

    for (auto ele : vec) {
        list.push_back(ele);
    }
    

    你可能想写:

    for (auto& ele : vec) {
        list.push_back(ele);
    }
    

    当开始使用侵入式容器时,这是经典的困惑:没有什么能像所有标准库容器一样具有价值。

    为避免此类情况,请考虑使用自动取消链接挂钩模式。

    演示

    甚至比必须考虑对循环变量进行引用限定更安全的是,根本没有循环:

    boost::intrusive::list<X> list(vec.begin(), vec.end());
    

    Live On Coliru

    #include <iostream>
    #include <iterator>
    #include <vector>
    #include <boost/intrusive/list.hpp>
    
    struct X : public boost::intrusive::list_base_hook<> {
        X(int a_in) : a{a_in} {}
        int a;
    
        friend std::ostream& operator<<(std::ostream& os, X const& x) { return os << "{" << x.a << "}"; }
    };
    
    int main() {
        std::ostream_iterator<X> out(std::cout << std::unitbuf, " ");
    
        std::vector<X> vec { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        boost::intrusive::list<X> list(vec.begin(), vec.end());
    
        std::cout << "before: "; std::copy(list.begin(), list.end(), out);
    
        list.remove_if([](X const& x) { return 0 == (x.a % 2); });
    
        std::cout << "\nafter: "; std::copy(list.begin(), list.end(), out);
    }
    

    打印

    before: {1} {2} {3} {4} {5} {6} {7} {8} {9} {10} 
    after: {1} {3} {5} {7} {9} 
    

    与auto_unlink:

    struct X : public bi::list_base_hook<bi::link_mode<bi::auto_unlink> > {
    

    注意,您需要禁用对list&lt;&gt; 的恒定时间size() 支持(请参阅reference)

    有了它,甚至添加

    vec.erase(vec.begin()+4);
    

    将正确地从侵入列表中取消相应节点的链接:

    Live On Coliru

    #include <iostream>
    #include <iterator>
    #include <vector>
    #include <boost/intrusive/list.hpp>
    
    namespace bi = boost::intrusive;
    
    struct X : public bi::list_base_hook<bi::link_mode<bi::auto_unlink> > {
        X(int a_in) : a{a_in} {}
        int a;
    
        friend std::ostream& operator<<(std::ostream& os, X const& x) { return os << "{" << x.a << "}"; }
    };
    
    int main() {
        std::ostream_iterator<X> out(std::cout << std::unitbuf, " ");
    
        std::vector<X> vec { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        bi::list<X, bi::constant_time_size<false> > list(vec.begin(), vec.end());
    
        std::cout << "before: "; std::copy(list.begin(), list.end(), out);
    
        list.remove_if([](X const& x) { return 0 == (x.a % 2); });
    
        std::cout << "\nafter: "; std::copy(list.begin(), list.end(), out);
    
        vec.erase(vec.begin()+4);
        std::cout << "\nauto-unlinked: "; std::copy(list.begin(), list.end(), out);
    }
    

    打印

    before: {1} {2} {3} {4} {5} {6} {7} {8} {9} {10} 
    after: {1} {3} {5} {7} {9} 
    auto-unlinked: {1} {3} {6} {8} {10} 
    

    【讨论】:

    • 添加了带和不带自动取消链接模式的演示;还有一些风格提示
    • 呃facepalm
    • 我们都去过那里。好消息是,您的问题代码非常好。干净、中肯、独立。继续杀戮:)
    • ostream_iterator 的有趣构造。不能多次投票,哈哈,但是??
    猜你喜欢
    • 2013-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-13
    • 1970-01-01
    • 2013-06-24
    • 1970-01-01
    相关资源
    最近更新 更多