Boost logo

Boost Users :

Subject: [Boost-users] [multiindex] custom key extractor problem
From: Stephan Menzel (stephan.menzel_at_[hidden])
Date: 2008-12-04 13:13:07


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.


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net