使用内部迭代器从提升多索引中删除项目时的一致性
Consistency when removing items from boost multi-index using an inner iterator
假设我正在使用两个索引之一迭代 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
迭代器是否总是有效的?谢谢!
您的循环可能存在根本性缺陷。我认为这是因为您使用了令人困惑的名称(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;
Note the code will remove remove 'Ruby Smith (age 34)' just fine. The 'John' criterion is never used, so:
更好的是,将其修复为等价物:
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;
}
跳出框框思考
看起来你真的想通过一些 "primary" 键(名字,last_name,年龄)删除。说出你的意思:
pc.erase(pc.find(boost::make_tuple("Smith", "John", 34))); // just the one
这是代码的全部。
#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};
假设我正在使用两个索引之一迭代 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
迭代器是否总是有效的?谢谢!
您的循环可能存在根本性缺陷。我认为这是因为您使用了令人困惑的名称(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;
Note the code will remove remove 'Ruby Smith (age 34)' just fine. The 'John' criterion is never used, so:
更好的是,将其修复为等价物:
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;
}
跳出框框思考
看起来你真的想通过一些 "primary" 键(名字,last_name,年龄)删除。说出你的意思:
pc.erase(pc.find(boost::make_tuple("Smith", "John", 34))); // just the one
这是代码的全部。
#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};