Sign in to follow this  
azherdev

[C++] std::list swapping elements, how?

Recommended Posts

I am having a difficulty figuring out how to swap two items in a list. I have a list which holds pointers to an object. The object is rendered in the order it was inserted into the list. Now, based on some logic, I need to swap two items in the list so that their order changes when rendering. How can I do that? std::list<MyObject*> objs; objs.push_back(new MyObject("one")); objs.push_back(new MyObject("two")); objs.push_back(new MyObject("three")); objs.push_back(new MyObject("four")); objs.push_back(new MyObject("five")); Now, the list is in the order I pushed back the objects. But how can I swap MyObject pointer "five" with "three"? Any help would be greatly appreciated. Thank you all.

Share this post


Link to post
Share on other sites
you could switch to a deque. but u can swap elements with a list too with two iterators.

list<int> mylist;
mylist.push_back(1);
mylist.push_back(2);
mylist.push_back(3);
mylist.push_back(4);
mylist.push_back(5);

list<int>::iterator i = mylist.begin();
list<int>::iterator j = mylist.begin();
j++; j++; j++;
cout << (*i) << endl;
cout << (*j) << endl;
int temp = *i;
*i = *j;
*j = temp;
cout << (*i) << endl;
cout << (*j) << endl;

Share this post


Link to post
Share on other sites
Same way you swap anything in C++, std::swap(*iteratorAtThree,*iteratorAtFive);

If the logic is some kind of sort operation that you will be applying to each element, make it perform like operator<() and write a functor for it:


struct DrawSorter {
bool operator()( const MyObject *one, const MyObject *two ) const {
return one->sortOrder < two->sortOrder;
}
};

objs.sort(DrawSorter());


Share this post


Link to post
Share on other sites
How exactly is it that you come to know that two particular objects need to be swapped? What relates the two particular objects together? A comparison?
Is this some kind of sort or partial sort? It sounds like it is. If so, you're asking the wrong question, and should instead be asking how to sort the list (a higher level goal).
You may also be using the wrong container type.

What is the higher level goal here - Swapping helps achieve what?

Share this post


Link to post
Share on other sites
I am using a list to hold UI objects ( form, button, checkbox, etc ). The list is populated in the order that the objects are created. During rendering, I render the objects in the order they appear in the list. But, I need to introduce the functionality that when an object ( form 1 ) comes into focus, it is swapped with any other form within the list that is at the end of the list. This way, when the renderer draws the form 1, it is draw on top of any other forms that may have been drawn.

Share this post


Link to post
Share on other sites
Here is the code in that function:

m_controls is the std::list that holds all the controls.
BringToFront is a function that all the controls have.

What I am trying to do is simply swap the control calling it (this) with whatever control is at the end of the list. I can not remove and push_back because this function is called within an iterator for the list.



void BringToFront(void)
{
std::list<TvControl*>::iterator from = this->m_form_manager->m_controls.end();
std::list<TvControl*>::iterator to = std::find(this->m_form_manager->m_controls.begin(), this->m_form_manager->m_controls.end(), this);

if ( (*from) != this )
{
TvControl* tmp;
tmp = *from;
from = to;
*to = tmp;
}
}



This code breaks, compiles but gives: list iterator not dereferencable error in the if statement. I'm confused by the pointers here, anyone can help?

Share this post


Link to post
Share on other sites
Quote:
Original post by rip-off
Same way you swap anything in C++, std::swap(*iteratorAtThree,*iteratorAtFive);

If the logic is some kind of sort operation that you will be applying to each element, make it perform like operator<() and write a functor for it:

*** Source Snippet Removed ***


Or, since you are using iterators, std::iter_swap():


jfl.

Share this post


Link to post
Share on other sites
Thanks jflanglois! I was looking in the wrong place. I have updated my function to this:


void TvControl::BringToFront(void)
{
std::list<TvControl*>::iterator from = std::find(
this->m_form_manager->m_controls.begin(),
this->m_form_manager->m_controls.end(),
this->m_form_manager->m_controls.back());

std::list<TvControl*>::iterator to = std::find(
this->m_form_manager->m_controls.begin(),
this->m_form_manager->m_controls.end(),
this);

std::iter_swap(from, to);
}




and now it works as desired! Thank you all!

Share this post


Link to post
Share on other sites
Quote:
Original post by azherdev
Thanks jflanglois! I was looking in the wrong place. I have updated my function to this:

*** Source Snippet Removed ***

and now it works as desired! Thank you all!


Note that std::swap() would have worked fine as well. Your code was simply wrong because you were assigning iterators, not pointed-to elements.

Note also that you can simplify your code:

void TvControl::BringToFront()
{
std::iter_swap(
std::find(
m_form_manager->m_controls.rbegin(),
m_form_manager->m_controls.rend(),
this ),
m_form_manager->m_controls.rbegin() );
}





You don't need to explicitly use this for members. You might also consider making m_form_manager a non-pointer.

Also, don't use void to denote no parameters, that's a C construct.

Finally, I'm not too sure about controls having a reference to the container they're in, much less modifying their own position.


jfl.

Share this post


Link to post
Share on other sites
Quote:
Original post by azherdev
I am using a list to hold UI objects ( form, button, checkbox, etc ). The list is populated in the order that the objects are created. During rendering, I render the objects in the order they appear in the list. But, I need to introduce the functionality that when an object ( form 1 ) comes into focus, it is swapped with any other form within the list that is at the end of the list. This way, when the renderer draws the form 1, it is draw on top of any other forms that may have been drawn.
Ah cool, that's fine then. That's a perfectly valid reason. It still helps to explain more about what you're doing straight off though.[smile]

Given the operations you're performing on the list you might find that a vector is just as suitable, if not more.

Share this post


Link to post
Share on other sites
Thank you guys for helping. I've implemented it probably not the most efficient way but there are no memor leaks and my bottlenecks are rendering related. I appreciate all the help.

I'll optimize it when the logic is working as desired... yeah... right... :)

Share this post


Link to post
Share on other sites
Quote:
Original post by azherdev
I am using a list to hold UI objects ( form, button, checkbox, etc ). The list is populated in the order that the objects are created. During rendering, I render the objects in the order they appear in the list. But, I need to introduce the functionality that when an object ( form 1 ) comes into focus, it is swapped with any other form within the list that is at the end of the list. This way, when the renderer draws the form 1, it is draw on top of any other forms that may have been drawn.

Surely swapping it with the top most form wont always give the correct rendering order?

Suppose you have 3 overlapping forms ('A' on top of 'B' on top of 'C') so the current rendering order is C-B-A, now the user clicks on C which is at the back, the correct rendering order (like you would expect in MS Windows with C simply brought to focus) would be B-A-C, but because you're swapping C with A what you actually have is A-B-C, so you will suddenly see form A jump to the back unexpectedly.

I think you should redesign your logic so you can remove from the list and push_back at the end which would result in conventional windows form behaviour. I dont think widgets should control their own rendering order the way you have it currently.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this