[multiindex] custom key extractor problem

Hi everyone, I could need a little advice using boost multiindex as follows: I have a Host class and I want to store HostPtrs in a multiindex container to a) have a member ip() as a key to unique hosts and b) be able to access random hosts via operator[]. The problem as I understand is the shared_ptr. Please consider this: class Host { public: Host(const boost::asio::ip::address &ip) : m_ip(ip) {}; const boost::asio::ip::address &ip(void) const throw () { return m_ip; }; private: Host(void) {}; boost::asio::ip::address m_ip; }; typedef boost::shared_ptr<Host> HostPtr; struct lthost { bool operator()(const HostPtr &h1, const HostPtr &h2) const { return (h1->ip() < h2->ip()); } }; struct giveip { // this is supposedly my key extractor typedef boost::asio::ip::address result_type; const result_type &operator()(const HostPtr &p) const { return p->ip(); }; }; typedef boost::multi_index_container< HostPtr, boost::multi_index::indexed_by< boost::multi_index::ordered_unique<giveip>, boost::multi_index::random_access<> >
HostSet;
typedef HostSet::nth_index<0>::type HostSetOrderedIndex; typedef HostSet::nth_index<1>::type HostSetRandomIndex; Now inserting and accessing elements compiles fine, just when I try to erase something... int main(int argc, char **argv) { HostSet s; HostPtr p1(new Host(boost::asio::ip::address::from_string("127.0.0.1"))); HostPtr p2(new Host(boost::asio::ip::address::from_string("10.10.55.1"))); // now place a pointer to that host in the multiset. HostSetOrderedIndex &oi = s.get<0>(); oi.insert(p1); oi.insert(p2); oi.erase(p1); // booom } Basically, I want the index to access each ptr's ip() function to get the key rather than the ptr itself, which would be just random mem as far as I understand it. So the key extractor should work, shouldn't it? I also tried the lthost() function: typedef boost::multi_index_container< HostPtr, boost::multi_index::indexed_by< boost::multi_index::ordered_unique<boost::multi_index::identity<HostPtr>, lthost>, boost::multi_index::random_access<> >
But that doesn't work either. I guess it's accessing the HostPtr directly instead of dereferencing it. It does compile and also does the job but tests have shown that when I do this: HostSetOrderedIndex &oi = s.get<0>(); oi.insert(p2); HostSetRandomIndex &hsri = s.get<1>(); hsri.sort(); and then iterate over the container (hsri) the order will vary. Sometimes one of the hosts appears at [0] sometimes the other. I'm quite puzzled how this is supposed to work. Can you give me some hints?? Thanks a lot, Stephan PS: I know, the use case is kinda weird. Basically, I want to be able to insert elements with the set logic, and only the IP shall count as identity. Access via random access index is necessary to do hashing in a stable deterministic way over the container.

Bugzilla from stephan.menzel@gmx.eu wrote:
Hi everyone,
I could need a little advice using boost multiindex as follows: I have a Host class and I want to store HostPtrs in a multiindex container to a) have a member ip() as a key to unique hosts and b) be able to access random hosts via operator[]. The problem as I understand is the shared_ptr. [...] int main(int argc, char **argv) {
HostSet s;
HostPtr p1(new Host(boost::asio::ip::address::from_string("127.0.0.1"))); HostPtr p2(new Host(boost::asio::ip::address::from_string("10.10.55.1")));
// now place a pointer to that host in the multiset. HostSetOrderedIndex &oi = s.get<0>(); oi.insert(p1); oi.insert(p2);
oi.erase(p1); // booom }
This can't possibly compile: erase() can accept either an iterator or a key, and p1 is neither. You can write: oi.erase(p1->ip()); and everything compiles and works just fine. Your key for HostSetOrderedIndex is std::string, which is exactly what you want AFAICS.
Basically, I want the index to access each ptr's ip() function to get the key rather than the ptr itself, which would be just random mem as far as I understand it. So the key extractor should work, shouldn't it?
Yes, this is what you currently have, HostPtrs are indexed by IP. And the key extractor works, it's only the confusion about erase that I think is misleading you.
I also tried the lthost() function:
typedef boost::multi_index_container< HostPtr, boost::multi_index::indexed_by<
boost::multi_index::ordered_unique<boost::multi_index::identity<HostPtr>, lthost>, boost::multi_index::random_access<> >
In this variation the key is HostPtr, which are sorted by their IPs. Noy you could legitimately use oi.erase(p1), for instance, though the former version is probably better because it allows you to lookup passing only a string instead of a whole HostPtr, which is more expensive to create.
But that doesn't work either. I guess it's accessing the HostPtr directly instead of dereferencing it. It does compile and also does the job but tests have shown that when I do this:
HostSetOrderedIndex &oi = s.get<0>(); oi.insert(p2);
HostSetRandomIndex &hsri = s.get<1>(); hsri.sort();
and then iterate over the container (hsri) the order will vary. Sometimes one of the hosts appears at [0] sometimes the other.
This is because hsri.sort() does the sorting based on std::less<HostPtr>, which is not what you want. Write this instead: hsri.sort(lthost()); to explicitly specify that you want your elements sorted according to lthost. Note that the fact that HostSetOrderedIndex uses lthost does not affect in any manner the way HostSetRandomIndex operates. HTH, Joaquín M López Muñoz Telefónica, Investigación y Desarrollo -- View this message in context: http://www.nabble.com/-multiindex--custom-key-extractor-problem-tp20839161p2... Sent from the Boost - Users mailing list archive at Nabble.com.

Joaquin, Am Donnerstag, 4. Dezember 2008 21:18:36 schrieb Joaquin M Lopez Munoz:
HostSetOrderedIndex &oi = s.get<0>(); oi.insert(p1); oi.insert(p2);
oi.erase(p1); // booom }
This can't possibly compile: erase() can accept either an iterator or a key, and p1 is neither. You can write:
oi.erase(p1->ip());
D'ough! In the very minute before I read your mail I figured that out myself. Thanks a lot for confirming that. Now it seems so obvious. However, it does require the user to know about that giveip() magic and what I'm doing here, which is slightly different from the expected set semantics, but i'll hide it away anyway.
and everything compiles and works just fine. Your key for HostSetOrderedIndex is std::string, which is exactly what you want AFAICS.
...well, actually it's asio::ip::address but I get your point.
Yes, this is what you currently have, HostPtrs are indexed by IP. And the key extractor works, it's only the confusion about erase that I think is misleading you.
Indeed it was. Big time. Could one make this a little easier to code? I'll write some erase overload template for that.
In this variation the key is HostPtr, which are sorted by their IPs. Noy you could legitimately use oi.erase(p1), for instance, though the former version is probably better because it allows you to lookup passing only a string instead of a whole HostPtr, which is more expensive to create.
Is that so? I've had the impression that version was broken because it sorted by pointer value and...
This is because hsri.sort() does the sorting based on std::less<HostPtr>, which is not what you want. Write this instead:
hsri.sort(lthost());
...that was default and took the functor you give in at the declaration. Anyway, now I think you're just right and I can finally have peace of mind on that one.
to explicitly specify that you want your elements sorted according to lthost. Note that the fact that HostSetOrderedIndex uses lthost does not affect in any manner the way HostSetRandomIndex operates.
Ahhh, that is what you meant. I did specify lthost for the ordered index, but never for the random index. That's why the sort() went wrong. All right. It isn't possible to specify lthost for these operations in the RandomIndex parameters, is it? Anyway, just curious. One working version is just fine, especially since it's the more efficient one. Great lib, that MultiIndex! I just love it, and well documented too. Thanks for your help. Stephan

Bugzilla from stephan.menzel@gmx.eu wrote:
Joaquin,
Am Donnerstag, 4. Dezember 2008 21:18:36 schrieb Joaquin M Lopez Munoz:
and everything compiles and works just fine. Your key for HostSetOrderedIndex is std::string, which is exactly what you want AFAICS.
...well, actually it's asio::ip::address but I get your point.
Oh yes, sorry, I locally replaced asio::ip::address with std::string to compile your code with minimal hassle.
to explicitly specify that you want your elements sorted according to lthost. Note that the fact that HostSetOrderedIndex uses lthost does not affect in any manner the way HostSetRandomIndex operates.
Ahhh, that is what you meant. I did specify lthost for the ordered index, but never for the random index. That's why the sort() went wrong. All right. It isn't possible to specify lthost for these operations in the RandomIndex parameters, is it?
It isn't possible, random_acces roughly mimics std::list, which does not allows for the specification of any sorting predicate at declaration time.
Anyway, just curious. One working version is just fine, especially since it's the more efficient one.
Great lib, that MultiIndex! I just love it, and well documented too.
Glad to know it's being useful to you. Best, Joaquín M López Muñoz Telefónica, Investigación y Desarrollo -- View this message in context: http://www.nabble.com/-multiindex--custom-key-extractor-problem-tp20839161p2... Sent from the Boost - Users mailing list archive at Nabble.com.
participants (2)
-
Joaquin M Lopez Munoz
-
Stephan Menzel