使用内部迭代器从boost多索引中删除项目时的一致性

时间:2015-11-20 13:55:21

标签: c++ boost boost-multi-index

假设我使用两个索引之一迭代boost::multi_index。然后,如果我开始使用其他索引进行迭代并根据某些条件擦除元素,那么这会使上部迭代器失效吗?

如,

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/composite_key.hpp>

#include <string>
#include <iostream>

using namespace boost::multi_index;
using namespace std;

struct person {
    string name;
    string last_name;
    int age;
};

typedef multi_index_container<
    person,
    indexed_by<
        ordered_non_unique<member<person, string, &person::name> >,
        ordered_non_unique<member<person, int, &person::age> >,
        sequenced<>
    >
> PersonCollection;


int main()
{
     PersonCollection pc;
     //insert some elements into pc
     struct person kk = {"John", "Doe", 15};
     pc.insert(kk);
     kk = {"John", "Doe2", 17};
     pc.insert(kk);
     kk = {"John", "Doe3", 34};
     pc.insert(kk);
     kk = {"John", "Smith", 34};
     pc.insert(kk);

     auto &index0 = pc.get<0>();
     auto range0 = index0.equal_range("John");
     while (range0.first != range0.second) {
         auto &index1 = pc.get<1>();
         auto range1 = index1.equal_range(34);
         while (range1.first != range1.second) {
             if (range1.first->last_name == "Smith")
                 range1.first = index1.erase(range1.first);
             else
                 ++range1.first;    
         }
    ++range0.first;
    }
    return 0;
}

那么在这种情况下,range0迭代器是否始终有效?谢谢!

1 个答案:

答案 0 :(得分:1)

你的循环可能存在根本缺陷。我认为这是因为你使用了令人困惑的名字(range0等)。外部循环与内部循环无关,因此,您可以将其删除(节省时间进行无用的重复)。这是一个澄清的重写:

auto& ageIdx = pc.get<byAge>();

auto namerange = pc.get<byName>().equal_range("John");
for (auto name_it = namerange.first, end = namerange.second; name_it != end; ++name_it) {

    auto agerange = ageIdx.equal_range(34);

    for (auto age_it = agerange.first, end = agerange.second; age_it != end;) {
        if (age_it->last_name == "Smith")
            age_it = ageIdx.erase(age_it);
        else
            ++age_it;    
    }
}

确实这是不安全的。 name_it可能无效。解决它:

for (auto name_it = namerange.first, end = namerange.second; name_it != end;) {
    ++name_it;
  

请注意,该代码将删除删除&#39; Ruby Smith(34岁)&#39;正好。约翰&#39;从不使用标准,所以:

更好的是,将其修改为等效的:

auto agerange = pc.get<byAge>().equal_range(34);

for (auto age_it = agerange.first, end = agerange.second; age_it != end;) {
    std::cout << *age_it << "\n";
    if (age_it->last_name == "Smith")
        age_it = ageIdx.erase(age_it);
    else
        ++age_it;    
}

开箱即用

看起来你想删除一些&#34; primary&#34; key(name,last_name,age)。说出你的意思:

pc.erase(pc.find(boost::make_tuple("Smith", "John", 34))); // just the one

代码的全部

<强> Live On Coliru

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <string>
#include <iostream>

struct person {
    std::string name;
    std::string last_name;
    int age;

    friend std::ostream& operator<<(std::ostream& os, person const& p) {
        return os << "{" << p.name << ", " << p.last_name << ", " << p.age << "}";
    }
};

namespace bmi = boost::multi_index;

typedef bmi::multi_index_container<
    person,
    bmi::indexed_by<
        bmi::ordered_unique<bmi::tag<struct primaryKey>,
            bmi::composite_key<person,
                bmi::member<person, std::string, &person::last_name>,
                bmi::member<person, std::string, &person::name>,
                bmi::member<person, int,         &person::age>
            >
        >,
        bmi::ordered_non_unique<bmi::tag<struct byAge>,  bmi::member<person, int, &person::age> >
    >
> PersonCollection;

int main() {
    PersonCollection pc {
        person { "John",    "Lennon",    34 },
        person { "Elliot",  "Gardiner",  72 },
        person { "John",    "Smith",     34 },
        person { "Lucy",    "Greenstle", 34 },
        person { "Gold",    "Smith",     34 },
        person { "Nicolai", "Josuttis",  42 }
    };

    auto& idx = pc.get<primaryKey>();

    // print
    std::copy(pc.begin(), pc.end(), std::ostream_iterator<person>(std::cout << "\n", "; "));

    pc.erase(pc.find(boost::make_tuple("Smith", "John", 34))); // just the one
    // print
    std::copy(pc.begin(), pc.end(), std::ostream_iterator<person>(std::cout << "\n", "; "));

    auto range = idx.equal_range(boost::make_tuple("Smith", "John")); // any age
    for (auto f=range.first, l=range.second; f!=l;)
        f = idx.erase(f);
    // print
    std::copy(pc.begin(), pc.end(), std::ostream_iterator<person>(std::cout << "\n", "; "));

    range = idx.equal_range(boost::make_tuple("Smith")); // any age/first name
    for (auto f=range.first, l=range.second; f!=l;)
        f = idx.erase(f);

    // print
    std::copy(pc.begin(), pc.end(), std::ostream_iterator<person>(std::cout << "\n", "; "));
}

打印:

{Elliot, Gardiner, 72}; {Lucy, Greenstle, 34}; {Nicolai, Josuttis, 42}; {John, Lennon, 34}; {Gold, Smith, 34}; {John, Smith, 34}; 
{Elliot, Gardiner, 72}; {Lucy, Greenstle, 34}; {Nicolai, Josuttis, 42}; {John, Lennon, 34}; {Gold, Smith, 34}; 
{Elliot, Gardiner, 72}; {Lucy, Greenstle, 34}; {Nicolai, Josuttis, 42}; {John, Lennon, 34}; {Gold, Smith, 34}; 
{Elliot, Gardiner, 72}; {Lucy, Greenstle, 34}; {Nicolai, Josuttis, 42}; {John, Lennon, 34};