如何在迭代boost :: intrusive :: list时擦除

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在迭代boost :: intrusive :: list时擦除相关的知识,希望对你有一定的参考价值。

如何在迭代它时从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;
    }
}
答案

你的问题是你已经把临时工推入了清单:

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 << "
after: "; 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> > {

注意,你需要禁用size()的恒定时间list<>支持(参见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 << "
after: "; std::copy(list.begin(), list.end(), out);

    vec.erase(vec.begin()+4);
    std::cout << "
auto-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} 

以上是关于如何在迭代boost :: intrusive :: list时擦除的主要内容,如果未能解决你的问题,请参考以下文章

Boost::Intrusive 中 splay_multiset 的成员钩子实现

boost serialization: intrusive and non-intrusive

boost::Unique_Ptr 对象列表

如何在 R studio 的 Caret 中抑制 Boosted 树模型 gbm 的迭代输出

使用 boost 侵入式指针初始化数组的最时尚方式

如果这些子节点本身有子节点,如何迭代 boost::propertytree 中的子节点?