如何在迭代时擦除 boost::intrusive::list
How to erase while iterating 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());
#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> > {
Note, you need to disable constant-time size()
support for the list<>
(see reference)
有了这个,甚至添加
vec.erase(vec.begin()+4);
将正确地从侵入列表中取消链接相应的节点:
#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}
如何在迭代时从 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());
#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> > {
Note, you need to disable constant-time
size()
support for thelist<>
(see reference)
有了这个,甚至添加
vec.erase(vec.begin()+4);
将正确地从侵入列表中取消链接相应的节点:
#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}