Hi, All, I just have started using boost and have some questions, answers on that i couldn’t find in the documentation. My interest is in using multi_index_container as combination of advantages of standard bidirectional list as well as fast lookup (insertion) of standard associative container (particularly set). Let’s say we have the following definitions: typedef boost::multi_index_container< UserInfo, boost::multi_index::indexed_by< boost::multi_index::sequenced<>, boost::multi_index::ordered_unique< boost::multi_index::identity<UserInfo>, UserInfoLess> > > UsersContainer; typedef UsersContainer::nth_index<0>::type UsersList; typedef UsersContainer::nth_index<1>::type UsersSet; Now we want to insert some value into this container the following way: UsersSet& setIndex = m_Users.get<1>(); std::pair<UsersSet::iterator, bool> insRet = setIndex.insert(someVal); The question is how can i acquire iterator of m_Users having the iterator UsersSet::iterator ? Do iterators keep the property of set’s iterators that they remain valid after insertion of an element? Thanks for the answers, Vladimir Voronkov.
On Tuesday, October 13, 2009 9:53 AM, Vladimir Voronkov wrote:
Hi, All,
I just have started using boost and have some questions, answers on that i couldn’t find in the documentation.
My interest is in using multi_index_container as combination of advantages of standard bidirectional list as well as fast lookup (insertion) of standard associative container (particularly set).
Let’s say we have the following definitions:
typedef boost::multi_index_container< UserInfo, boost::multi_index::indexed_by< boost::multi_index::sequenced<>, boost::multi_index::ordered_unique< boost::multi_index::identity<UserInfo>, UserInfoLess> > > UsersContainer;
typedef UsersContainer::nth_index<0>::type UsersList; typedef UsersContainer::nth_index<1>::type UsersSet;
Now we want to insert some value into this container the following way:
UsersSet& setIndex = m_Users.get<1>(); std::pair<UsersSet::iterator, bool> insRet = setIndex.insert(someVal);
The question is how can i acquire iterator of m_Users having the iterator UsersSet::iterator ? Do iterators keep the property of set’s iterators that they remain valid after insertion of an element?
Thanks for the answers, Vladimir Voronkov.
I would recommend reading up on iterator projection. http://www.boost.org/doc/libs/1_40_0/libs/multi_index/doc/tutorial/basics.ht... As far as I know, all iterators to all indices of a multi-index remain valid unless they point to a deleted element.
Andrew Holden <aholden <at> charteroaksystems.com> writes:
On Tuesday, October 13, 2009 9:53 AM, Vladimir Voronkov wrote:
Do iterators keep the property of set’s iterators that they remain valid after insertion of an element? [...]
As far as I know, all iterators to all indices of a multi-index remain valid unless they point to a deleted element.
This is correct. Joaquín M López Muñoz Telefónica, Investigación y Desarrollo
Hi again, Thanks for the answers, they helped my. Now I have come with some another probably stupid questions. I've changed the initial example by adding some attribute to the element. Let's say int. typedef std::string UserInfo; typedef std::less<std::string> UserInfoLess; typedef boost::multi_index_container< std::pair<UserInfo, int>, boost::multi_index::indexed_by< boost::multi_index::sequenced<>, boost::multi_index::ordered_unique< boost::multi_index::member<std::pair<UserInfo, int>, UserInfo, &std::pair<UserInfo, int>::first>, UserInfoLess>, boost::multi_index::ordered_non_unique< boost::multi_index::member<std::pair<UserInfo, int>, int, &std::pair<UserInfo, int>::second> > > > UsersContainer; typedef UsersContainer::nth_index<2>::type UsersSelected; This flag has not many possible values and most probably there will be many pairs in the container with the same value of this flag. Now I want to enumerate all values in the container with some specific value of this flag. There are many ways to do that. 1. Use lower_bound for getting iterator for the UsersSelected index. 2. implement own iterator that use some int value as a parameter. But the ideal solution would be to expose some kind of "view" of the container that behaves like list, so we could use it's iterator from begin() to end() taking only necessary elements. Is that possible? Thanks.
-----Original Message----- From: boost-users-bounces@lists.boost.org [mailto:boost-users- bounces@lists.boost.org] On Behalf Of Joaquin M Lopez Munoz Sent: Tuesday, October 13, 2009 8:16 PM To: boost-users@lists.boost.org Subject: Re: [Boost-users] multi_index_comtainer questions
Andrew Holden <aholden <at> charteroaksystems.com> writes:
On Tuesday, October 13, 2009 9:53 AM, Vladimir Voronkov wrote:
Do iterators keep the property of set’s iterators that they remain valid after insertion of an element? [...]
As far as I know, all iterators to all indices of a multi-index remain valid unless they point to a deleted element.
This is correct.
Joaquín M López Muñoz Telefónica, Investigación y Desarrollo
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
Vladimir Voronkov <voronkovv <at> mail.ru> writes:
Hi again,
Thanks for the answers, they helped my. Now I have come with some another probably stupid questions.
I've changed the initial example by adding some attribute to the element. Let's say int.
[...]
typedef UsersContainer::nth_index<2>::type UsersSelected;
This flag has not many possible values and most probably there will be many pairs in the container with the same value of this flag. Now I want to enumerate all values in the container with some specific value of this flag. There are many ways to do that. 1. Use lower_bound for getting iterator for the UsersSelected index. 2. implement own iterator that use some int value as a parameter.
But the ideal solution would be to expose some kind of "view" of the container that behaves like list, so we could use it's iterator from begin() to end() taking only necessary elements.
Is that possible?
The closest you can get to that, I guess, is to use equal_range(n), which returns a pair of iterators defining the range of elements with second==n (similar as the "begin()" and "end()" iterators you're after.) HTH, Joaquín M López Muñoz Telefónica, Investigación y Desarrollo
Vladimir Voronkov wrote on Thursday, October 15, 2009 10:20 AM:
Hi again,
Thanks for the answers, they helped my. Now I have come with some another probably stupid questions.
I've changed the initial example by adding some attribute to the element. Let's say int.
typedef std::string UserInfo; typedef std::less<std::string> UserInfoLess;
typedef boost::multi_index_container< std::pair<UserInfo, int>, boost::multi_index::indexed_by< boost::multi_index::sequenced<>, boost::multi_index::ordered_unique< boost::multi_index::member<std::pair<UserInfo, int>, UserInfo, &std::pair<UserInfo, int>::first>, UserInfoLess>, boost::multi_index::ordered_non_unique< boost::multi_index::member<std::pair<UserInfo, int>, int, &std::pair<UserInfo, int>::second> >
UsersContainer;
typedef UsersContainer::nth_index<2>::type UsersSelected;
This flag has not many possible values and most probably there will be many pairs in the container with the > same value of this flag. Now I want to enumerate all values in the container with some specific value of this flag. There are many ways to do that.
1. Use lower_bound for getting iterator for the UsersSelected index. 2. implement own iterator that use some int value as a parameter.
But the ideal solution would be to expose some kind of "view" of the container that behaves like list, so we > could use it's iterator from begin() to end() taking only necessary elements.
I have found this to be a very common use case for multi-index containers. I normally use ordered indices and composite keys to do this. Specifically, I would recommend the following index: boost::multi_index::ordered_unique //ordered_non_unique will also work < boost::multi_index::composite_key < std::pair<UserInfo, int>, boost::multi_index::member<std::pair<UserInfo, int>, int, &std::pair<UserInfo, int>::second>, boost::multi_index::member<std::pair<UserInfo, int>, UserInfo, &std::pair<UserInfo, int>::first> >
typedef UsersContainer::nth_index<2>::type::iterator UsersByFlagIterator; You can now get a sorted list of all users with a certain flag using: std::pair<UsersByFlagIterator, UsersByFlagIterator> range = my_container::get<2>().equal_range(boost::make_tuple(desired_flag)); This index can also find a specific flag, name combination like this: UsersByFlagIterator entry = my_container::get<2>().find(boost::make_tuple(desired_flag, desired_name));
-----Original Message----- From: boost-users-bounces@lists.boost.org [mailto:boost-users- bounces@lists.boost.org] On Behalf Of Joaquin M Lopez Munoz Sent: Tuesday, October 13, 2009 8:16 PM To: boost-users@lists.boost.org Subject: Re: [Boost-users] multi_index_comtainer questions
Andrew Holden <aholden <at> charteroaksystems.com> writes:
On Tuesday, October 13, 2009 9:53 AM, Vladimir Voronkov wrote:
Do iterators keep the property of set’s iterators that they remain valid after insertion of an element? [...]
As far as I know, all iterators to all indices of a multi-index remain valid unless they point to a deleted element.
This is correct.
Joaquín M López Muñoz Telefónica, Investigación y Desarrollo
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
I understand the idea with exposing interval for interator. This is not always useful. For example I implement some class with this container as a private member. I would expose useful interface from this class which hides all work with these flags as well as data representation. And at the same time I would like to avoid copying data into another container just to expose the necessary data. Imagine the following function. UsersSelected& MyClass::GetSelectedUsers() const { return m_container.get<2>(--- here we would put some condition ---); } Client of this code might not be aware of what container "UsersSelected" is, and just use it as regular set. This interface seems me more elegant then returning range of iterators because client should know what lies behind these iterators.
-----Original Message----- From: boost-users-bounces@lists.boost.org [mailto:boost-users- bounces@lists.boost.org] On Behalf Of Andrew Holden Sent: Friday, October 16, 2009 6:29 PM To: boost-users@lists.boost.org Subject: Re: [Boost-users] multi_index_comtainer questions
Vladimir Voronkov wrote on Thursday, October 15, 2009 10:20 AM:
Hi again,
Thanks for the answers, they helped my. Now I have come with some another probably stupid questions.
I've changed the initial example by adding some attribute to the element. Let's say int.
typedef std::string UserInfo; typedef std::less<std::string> UserInfoLess;
typedef boost::multi_index_container< std::pair<UserInfo, int>, boost::multi_index::indexed_by< boost::multi_index::sequenced<>, boost::multi_index::ordered_unique< boost::multi_index::member<std::pair<UserInfo, int>, UserInfo, &std::pair<UserInfo, int>::first>, UserInfoLess>, boost::multi_index::ordered_non_unique< boost::multi_index::member<std::pair<UserInfo, int>, int, &std::pair<UserInfo, int>::second> >
UsersContainer;
typedef UsersContainer::nth_index<2>::type UsersSelected;
This flag has not many possible values and most probably there will be many pairs in the container with the > same value of this flag. Now I want to enumerate all values in the container with some specific value of this flag. There are many ways to do that.
1. Use lower_bound for getting iterator for the UsersSelected index. 2. implement own iterator that use some int value as a parameter.
But the ideal solution would be to expose some kind of "view" of the container that behaves like list, so we > could use it's iterator from begin() to end() taking only necessary elements.
I have found this to be a very common use case for multi-index containers. I normally use ordered indices and composite keys to do this. Specifically, I would recommend the following index:
boost::multi_index::ordered_unique //ordered_non_unique will also work < boost::multi_index::composite_key < std::pair<UserInfo, int>, boost::multi_index::member<std::pair<UserInfo, int>, int, &std::pair<UserInfo, int>::second>, boost::multi_index::member<std::pair<UserInfo, int>, UserInfo, &std::pair<UserInfo, int>::first>
typedef UsersContainer::nth_index<2>::type::iterator UsersByFlagIterator;
You can now get a sorted list of all users with a certain flag using:
std::pair<UsersByFlagIterator, UsersByFlagIterator> range = my_container::get<2>().equal_range(boost::make_tuple(desired_flag));
This index can also find a specific flag, name combination like this:
UsersByFlagIterator entry = my_container::get<2>().find(boost::make_tuple(desired_flag, desired_name));
-----Original Message----- From: boost-users-bounces@lists.boost.org [mailto:boost-users- bounces@lists.boost.org] On Behalf Of Joaquin M Lopez Munoz Sent: Tuesday, October 13, 2009 8:16 PM To: boost-users@lists.boost.org Subject: Re: [Boost-users] multi_index_comtainer questions
Andrew Holden <aholden <at> charteroaksystems.com> writes:
On Tuesday, October 13, 2009 9:53 AM, Vladimir Voronkov wrote:
Do iterators keep the property of set’s iterators that they remain valid after insertion of an element? [...]
As far as I know, all iterators to all indices of a multi-index remain valid unless they point to a deleted element.
This is correct.
Joaquín M López Muñoz Telefónica, Investigación y Desarrollo
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
Vladimir Voronkov escribió:
I understand the idea with exposing interval for interator. This is not always useful. For example I implement some class with this container as a private member. I would expose useful interface from this class which hides all work with these flags as well as data representation. And at the same time I would like to avoid copying data into another container just to expose the necessary data. Imagine the following function.
UsersSelected& MyClass::GetSelectedUsers() const { return m_container.get<2>(--- here we would put some condition ---); }
Client of this code might not be aware of what container "UsersSelected" is, and just use it as regular set. This interface seems me more elegant then returning range of iterators because client should know what lies behind these iterators.
[Please don't top-post, see http://www.boost.org/community/policy.html#quoting ] I understand your position, and the short answer is that Boost.MultiIndex does not provide such a facility. A longer answer is, I don't really see this pseudo- container approach more beneficial than exposing a pair of iterators, because ranges (pair of iterators) are the preferred way to let different pieces of code communicate. This is the cornerstone of the STL design. Of course you might legitimately disagree. Joaquín M López Muñoz Telefónica, Investigación y Desarrollo
participants (4)
-
Andrew Holden
-
Joaquin M Lopez Munoz
-
joaquin@tid.es
-
Vladimir Voronkov