access random item in std::list?

Started by
16 comments, last by ToohrVyk 17 years, 1 month ago
there is some problem with the casting and i dont get it to work. And i need it to return a pointer anyway, so I tried to fix it and clean it up, but it doesnt work... (slump is my random int generator)

template<typename T>typename T* getRandom(T & list){  return= std::advance(list.begin(),slump(0,list.size()));}unit * u = getRandom(unitList);


//initializing' : cannot convert from 'class std::list<class unit *,class std::allocator<class unit *> > *' to 'class unit *'
Advertisement
Quote:Original post by suliman
there is some problem with the casting and i dont get it to work. And i need it to return a pointer anyway, so I tried to fix it and clean it up, but it doesnt work... (slump is my random int generator)

template<typename T>typename T* getRandom(T & list){  return= std::advance(list.begin(),slump(0,list.size()));}unit * u = getRandom(unitList);


//initializing' : cannot convert from 'class std::list<class unit *,class std::allocator<class unit *> > *' to 'class unit *'


This happens because you changed the code without understanding what it does. In my code, T is a container type (list, vector, deque). You kept this property by keeping the argument T & list. So, your modified function returns a pointer to a list. See where the contradiction is?

My original code returned an iterator inside the list. This allows me to avoid having to look into the type of the list to determine what kind of object it contains. This makes the code simpler and also lets it work with less effort on other containers (should you, for instance, use a vector instead of a list). Besides, your code assumes that the function would somehow return a pointer, because you know that your list contains pointers — but, again, you're losing genericity since you'll have to write a non-pointer version for other list types.

In short, keep the function general (although you may specialize the random number generator if you wish) and dereference the returned iterator to get the element.

template<typename Container>typename Container::iterator & getRandom(Container & list){  return std::advance(list.begin(),slump(0,list.size()));}unit * u = * getRandom(unitList);
still doesnt work, even if not changing anything. And the earlier version didnt compile either, thats why i starting changing it in the first place. I now try your:

template<typename Container>
typename Container::iterator & getRandom(Container & list)
{
return std::advance(list.begin(),slump(0,list.size()));
}

unit * u = * getRandom(unitList); //call


If i include the call the compiler gives me
return' : cannot convert from 'void' to 'class std::list<class unit *,class std::allocator<class unit *> >::iterator &'

on the return line. But if i make no call the compiler gives no errors. So there's still something wrong here...

Thanks for helping out
Erik

You're right, there was an incorrect part in my code. It should have been:

template<typename Container>typename Container::iterator getRandom(Container & list){  typename Container::iterator it = list.begin();  std::advance(it,slump(0,list.size()));  return it;}unit * u = * getRandom(unitList);


[EDIT] Forgot to remove the darned reference as well.
A minor point perhaps, but don't return a reference to the local iterator, I'm pretty sure thats a bad idea.
I LOVE LOVE LOVE template!

but is there something wrong with the SIMPLE solutions I posted? Here it is again:
int unitIndex = rand() % myUnitList.size();unit *u = *advance(myUnitList.begin(), unitIndex);

You're jut spending so much trouble getting a generic version of something working. Get the non-generic verion working and understood, then make the generic version. Most people don't write a generic tree class, till they know how to write a tree class, etc.
dont know why but it crashes when doing it on a (working and tested) list and on a working vector it doesnt crash but returns a bugged pointer to some random data (points not to a real pointer). Same problem with my test:

template<typename Container>
typename Container::iterator & getRandom(Container & list)
{
typename Container::iterator it = list.begin();
int n=slump(0,list.size()-1);
for(int ii=0;ii<n;ii++)
it++;
return it;
}


BUT: This below works, but its not very generic. Its not even a function. It should be kinda the same thing, only this works, the other doesnt. And im not sure why not...

int n=slump(0,unitList.size()-1);
std::list<unit*>::iterator it = unitList.begin();
for(int ii=0;ii<n;ii++)
it++;
unit * u = *it;
rip-off was right: one shouldn't return the iterator by reference.

This topic is closed to new replies.

Advertisement