LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   c++ boost::ptr_container and std::random_shuffle (https://www.linuxquestions.org/questions/programming-9/c-boost-ptr_container-and-std-random_shuffle-601036/)

synss 11-20-2007 01:54 AM

c++ boost::ptr_container and std::random_shuffle
 
Hello, I have a C++ problem:

I have a base class for very simple objects, which are however non copyable. And I have containers of these objects : a vector and a tree (for the same objects, hence I need pointers). I use boost::ptr_vector for the vector and I would like to use it as well for the tree but it does not work because I need to std::random_shuffle the order of the objects in the tree.

It does not work because iterators on boost::ptr_vector return references and the std::swap used internally by std::random_shuffle panics on non-copyable objects, I actually need to shuffle the order of the pointers and not the order of the objects.

Now I use a std::vector of raw pointers but boost is much more convenient.

Is there a relatively simple solution to my problem ? (if it is not simple, raw pointers are OK)

osor 11-20-2007 10:53 PM

If you absolutely want to use boost::ptr_vector, all you have to do is create indirect iterators. For example, something like this works:
Code:

#include <algorithm>
#include <iostream>

#include <boost/ptr_container/ptr_vector.hpp>
#include <boost/noncopyable.hpp>

using std::cout;
using std::endl;
using std::random_shuffle;

using boost::noncopyable;
using boost::ptr_vector;

class Simple : private noncopyable {
        public:
                int a;
                Simple(int a = 0) : a(a) { }
};

const int max=10;

int main() {
        ptr_vector<Simple> svec;
        ptr_vector<Simple>::iterator svit;
        for(int i = 0; i < max; i++)
                svec.push_back(new Simple(i));
        random_shuffle(svec.begin().base(), svec.end().base());
        for(svit = svec.begin(); svit != svec.end(); svit++)
                cout << svit->a << endl;
        for(int i = 0; i < max; i++)
                delete svec.pop_back().release();
        return 0;
}

Notice the line in red. If we remove both instances of “.base()”, we get compilation errors telling us that our class cannot be copied.

Also notice that by doing this, you lose the main advantage of using boost::ptr_vector<Simple> over std::vector<Simple*> (at least in this situation). I guess it makes sense if you “break the rules” for only one operation but use the advantages of Boost during the rest of the time.

synss 11-20-2007 11:44 PM

Thank you! I have just tried and it works! and it is simple, too, I am impressed!

Yes, that is the only place where I should need to "break the rule" and the program gets a little simpler using boost. So this is perfect.

Thanks again!


All times are GMT -5. The time now is 09:27 PM.