Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I am wondering, how operator == works on list::iterator. I have list of pointers (there are no duplicities) and two iterators which should point to the same place in that list. When I compare directly iterators by == (or !=) I got inequality but when I compare values they are pointing to I got equality. I also tried list.erase on both of then and got the same result.
Example:
list<VirtVertex *> blockList;
void initBlockList(){
/* somehow fill blockList */
for(auto it = blockList.begin(); it != blockList.end(); ++it)
(*it)->BLPosition = it;
}
for(auto it = blockList.begin(); it != blockList.end(); ++it){
if(it == (*it)->BLPosition)
cout << "OK"; //no "OK" printed
if(*it == *((*it)->BLPosition))
cout << "OK"; //got "OK" everytime
}
I am wondering, how operator == works on list::iterator.
operator== on a list::iterator works as you would expect: it returns true if the iterators points to the same element in the same position in the list, or they are both ends.
When I compare directly iterators by == (or !=) I got inequality but when I compare values they are pointing to I got equality.
That's perfectly valid, given that an std::list can contain duplicates.
Two iterators compare equal if they point to the same element of the same container (or to the end). That is as true for all containers, including list.
Comparing values that the iterators point to or reference is not the same as comparing iterators. For a container like list that can contain multiple (duplicate) elements with the same value, two iterators may compare unequal, but the values they reference may be the same. Obviously, if two iterators compare equal, and they are not an end iterator, the values they reference will also compare equal (assuming the element/type has an appropriate comparison operator).
list.erase() invalidates existing iterators of a list, so using previously obtained iterators gives undefined behaviour. However, new iterators subsequently obtained from the list will have the same properties.
Related
This question already has answers here:
Using erase-remove_if idiom
(3 answers)
Closed 4 years ago.
I want to delete object from vector which has property set on specific value. In this example:
void RemoveUser(int val)
{
users.remove_if([val](User u)
{
return u.val == val;
});
}
I can remove specific user based on its val property. This works on std::list, but its not working on std::vector. How can I archieve same result on vector?
std::vector doesn't have a remove_if member. But there is a standard algorith, aptly named std::remove_if that can work in tandem with the vectors erase member function.
users.erase(remove_if(begin(users), end(users), [val](User const& u)
{
return u.val == val;
}), end(users));
First remove_if shifts the elements of the range, and returns an iterator past the end of all the "good ones". The vector is of the same size as when we started at this point. Now that iterator is fed to erase, which kills all of those items, from that "new end", to the "old end" of the vector.
The reason std::list implements its own member version of remove_if is to better utilize its node based structure. It doesn't have to do copies to shift elements around or delete them. For std::vector, the algorithm is the best we can do.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
I need a queue that must add/remove some structs I have, such as:
struct MyObject
{
int offset;
BYTE status, data1, data2;
double beatPos;
enum Status
{
isOff = 8,
isOn = 9,
};
}
When I .Add() an element, this queue must put the element at the correct position, due to the beatPos value, which must be ordered from the lower (top of the queue, i.e. the next element I'll pop) to the upper (the last element I'll extract from it).
I see there is std::priority_queue, but I'm not sure if I can select which is the field for the ordering.
Also, once I add some structs in the list, I'd like to remove the first element that have (for example) beatPos=1,567 (which could be in the middle of the list, for example; not necessarily at the beginning).
Any clues?
What you want is a std::multiset. It takes a compare template parameter and it is defaulted to std::less for the type the container is going to store but you can specify a different comparator. To do that we can create a lambda that will compare two MyObjects and return which object should have a higher priority based on the beatPos member
auto my_compare = [](const MyObject & lhs, const MyObject & rhs)
{
return lhs.beatPos < rhs.beatPos;
}
And then we can use that like
std::multiset<MyObject, decltype(my_compare)> data(my_compare);
This will give you an ordered container that can store multiple objects with the same beatPos and allow you access into the middle of the container.
You can use std::multiset with a user-defined comparator. For example:
bool MyObjectComp(const MyObject& lhs, const MyObject& rhs) {
return lhs.beatPos < rhs.beatPos;
}
typedef std::set<MyObject, MyObjectComp> MyObjectSet;
Now the ordering within MyObjectSet is always from lowest to highest beatPos. You can search using lower_bound() and upper_bound(), and you can get the smallest value using begin().
Note that due to the nature of double values (IEEE floating point), exact comparison may not work, so you can't necessarily say mySet.find(0.5) but you can say mySet.upper_bound(0.49999).
The same user-defined comparator can be used for priority_queue as well, but that container does not support searching for an element by value, which is one of your requirements.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I am creating function, which takes a vector of operators( different matrices). Operators can be provided in different ordering ( from the smallest to biggest or other way around).
I need to create for loop based on ordering
for(auto tr = operators.begin(); tr != operators.end() ; ++tr )
or
for(auto tr = operators.end(); tr != operators.begin() ; --tr )
content inside of loop stays same
is there any way how to do this automatically? maybe based on some help input parameter?
You can support this by having your function consume a pair of iterators (a "range") instead of a complete matrix or vector. For example:
template <typename Iterator>
void print(Iterator begin, Iterator end) {
for(auto tr = begin; tr != end; ++tr)
; // ...
}
This way, you can pass any sort of range in: forward, reverse, or others. This is how much of the STL is designed.
If you use a std::vector for example, you'd invoke the above like so:
std::vector<int> vec;
print(vec.begin(), vec.end()); // forward
print(vec.rbegin(), vec.rend()); // reverse
Although, technically, an end() iterator can often be decremented and dereferenced safely, you are relying on specific properties that not all iterators are guaranteed to have.
A number of standard containers [some introduced in C++11 do not] have both forward iterators (which iterate through elements in order) and reverse iterators (which iterate over elements in the opposite order). The counterparts of begin() and end() are rbegin() and rend() respectively.
This question already has answers here:
index or position in std::set
(3 answers)
Closed 6 years ago.
This question applies to both std::set and std::unsorted_set.
I have an iterator to an element in a set. I'd like to use the iterator to get an "index" for the element based on its location in the set.
For example, the indices for my set would be as follows:
int index = 0;
for(MySetType::iterator begin = mySet.begin(); begin != mySet.end(); begin++)
{
cout << "The index for this element is " << index;
index++;
}
I have tried doing arithmetic using iterators but it doesn't work:
int index = mySetIterator - mySet.begin();
Is there any way to use the iterator to get an index value like this based on its location in the set?
Use STL distance, namely std::distance(set.begin(), mySetIterator)
Please note that:
Returns the number of elements between first and last. The behavior
is undefined if last is not reachable from first by (possibly
repeatedly) incrementing first.
Remark : Complexity is linear;
However, if InputIt additionally meets the requirements of
LegacyRandomAccessIterator, complexity is constant.
std::set and set::unordered_set are associative containers, not sequence containers, hence the concept itself of index doesn't make much sense.
If you need to retrieve an index for an associative container then design should be changed (even because without a concept of least or most recent inserted element the indices in such containers are subject to change).
std::set has just a bidirectional iterator, which means you can't do what you're trying to do with operator + (or -). Those are only available to random access iterators, like std::vector provides.
You need to use std::distance to get the "index", and std::advance to move from the beginning of the set to the end.
auto distance = std::distance(mySet.begin(), someIterator);
auto it = mySet.begin();
std::advance(it, distance);
assert(it == someIterator);
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Can you remove elements from a std::list while iterating through it?
I have a loop in a function, that iterates over an std::list from begin to end.
In each cycle, I perform some checks and maybe do a few manipulations on the current list entry, and in some cases I want to remove it from the list.
Now, as expected my iterator gets invalidated.
Is there any way to work around this, to remove elements from a list while iterating over it?
Catch the return value of erase and use it as your iterator. The return value is an iterator to the next valid location after the erasure.
if(ShouldErase)
{
iter = list.erase(iter);
}
else
{
++iter;
}
Reference
Excerpt:
Return value
A bidirectional iterator pointing to the new location of the element that followed the last element erased by the function call, which is the list end if the operation erased the last element in the sequence.
Use postfix increment.
list.erase(it++);
it is increased, so it no longer refers to the erased element, then the previous value of it is given to list.erase. Make sure that you either do list.erase(it++) or ++it in your loop - doing both will skip elements and potentially increment past end of the list.
Have you considered using the list::remove_if algorithm?