gpt4 book ai didi

c++ - boost multi_index 反向迭代器删除麻烦

转载 作者:行者123 更新时间:2023-11-27 22:48:45 28 4
gpt4 key购买 nike

我有以下(简化的)代码:

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
namespace bmi = boost::multi_index;

#include <string>
#include <iostream>
#include <cassert>

using Container = boost::multi_index_container<
std::string,
bmi::indexed_by< bmi::ordered_non_unique< bmi::identity<std::string> > >
>;

/// Get the base of a non-reverse iterator. It's the iterator itself.
inline
Container::iterator const&
iter_base(Container::iterator const& it)
{
return it;
}

/** Get a non-reverse iterator that points at the same element as the given reverse_iterator.
*
* @param rit reverse_iterator
* @return a (non-reverse) iterator that points to the same element.
* @pre @p rit is dereferenceable (not equal to @c rend() of whatever container @p rit came from)
*/
inline
Container::iterator
iter_base(Container::reverse_iterator const& rit)
{
auto bit = rit.base();
// if 'rit' is a reverse iterator: &*(rit.base() - 1) == &*rit
return --bit;
}

template <typename IT>
void evict(Container& c, IT rb, IT fin)
{
std::vector<std::string> result;
for (; rb != fin; ) {
if (rb->size() == 3) {
auto victim = rb;
++rb;
std::cout << "victim->" << *victim << ", next->" << (rb==fin ? std::string{"THE END"} : *rb) << "\n";
auto next = c.erase(iter_base(victim));
std::cout << "size=" << c.size() << "\n";
for (auto const& s : c) {
std::cout << "remain: " << s << "\n"; // bar - baz - foo
}

rb = IT(next);
(void)next;
}
else {
result.push_back(*rb);
}
}
}

int main(int argc, char**)
{
bool forward = (argc == 1);

Container c;
c.insert("foo"); // will be last
c.insert("bar");
c.insert("baz");

if (forward) {
auto b = c.lower_bound("baz");

std::cout << ">> " << *b << "\n"; // prints baz

auto rb = (b);
std::cout << "<< " << *rb << "\n"; // prints baz
std::cout << "<< " << *iter_base(rb) << "\n"; // prints baz

evict(c, rb, c.end());
}
else {
auto b = c.upper_bound("baz");

std::cout << ">> " << *b << "\n"; // prints foo

auto rb = Container::reverse_iterator(b);
std::cout << "<< " << *rb << "\n"; // prints baz
std::cout << "<< " << *iter_base(rb) << "\n"; // prints baz

evict(c, rb, c.rend());
}
}

真正的代码不仅仅是删除,但这足以说明行为。

已编辑以表明在循环中不会发生任何删除。根据使用的迭代器类型,项目应该以正向或反向顺序添加到 result

当不带参数运行时,forward==true 并且输出符合预期:

>> baz
<< baz
<< baz
victim->baz, next->foo
size=2
remain: bar
remain: foo
victim->foo, next->THE END
size=1
remain: bar

当使用参数运行时,forward==false 输出为:

>> foo
<< baz
<< baz
victim->baz, next->bar
size=2
remain: bar
remain: foo
segmentation fault (core dumped)

(不符合预期)

使用地址清理器编译会在第 42 行(++rb 行)显示堆释放后使用。

似乎调用 erase(victim) 以某种方式使 rb 无效,即使 erase 不应该使任何其他迭代器无效。

知道我做错了什么吗?

最佳答案

第二个答案,OP 的额外要求是根据迭代器的性质以正序或逆序进行遍历。稍微小心一点,可以这样做:<罢工>

<罢工>
template <typename IT>
void evict(Container& c, IT rb, IT fin)
{
std::vector<std::string> result;
if(rb != fin) for(;;) {
IT next = rb;
++next;
bool finished = (next == fin);
if (rb->size() == 3) {
c.erase(iter_base(rb));
std::cout << "size=" << c.size() << "\n";
for (auto const& s : c) {
std::cout << "remain: " << s << "\n"; // bar - baz - foo
}
}
else {
result.push_back(*rb);
}
if(finished) break;
rb = next;
}
}

<罢工> 糟糕的是,受灾代码仍在运行到 UB。请试试这个:

template <typename IT>
void evict(Container& c, IT rb, IT fin)
{
std::vector<std::string> result;
if(rb != fin) for(;;) {
bool finished = (std::next(rb) == fin);
if (rb->size() == 3) {
rb = IT{c.erase(iter_base(rb))};
std::cout << "size=" << c.size() << "\n";
for (auto const& s : c) {
std::cout << "remain: " << s << "\n"; // bar - baz - foo
}

}
else {
result.push_back(*rb);
}
if(finished) break;
}
}

关于c++ - boost multi_index 反向迭代器删除麻烦,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40048092/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com