It is commonly understood that a good way to fully delete desired items from a std::vector is the erase-remove idiom.
As noted in the above link (as of the date of this posting), in code the erase-remove idiom looks like this:
int main()
{
// initialises a vector that holds the numbers from 0-9.
std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
// erase-remove idiom to completely eliminate the desired items from the vector
v.erase( std::remove( std::begin(v), std::end(v), 5 ), std::end(v) );
}
I would like to know whether a resize-remove idiom is equivalent in terms of functionality and performance to the erase-remove idiom. Or, perhaps I am missing something obvious?
Is the following resize-remove idiom equivalent to the above erase-remove idiom?
int main()
{
std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
// Is this "resize-remove" approach equivalent to the "erase-remove" idiom?
v.resize( std::remove( std::begin(v), std::end(v), 5 ) - v.begin() );
}
In my opinion, there are two reasons:
std::remove algorithm requires only Forward Iterator, but - op requires Random Access Iterator.
The result of std::remove means "the new end of container". Logically, we should erase [ "the new end of container" , "the old end of container" ).
It is equivalent for std::vector, but not for std::list or other containers. Not sure if subtracting iterators is even possible for std::list, and even if it is, it is a O(N) operation.
It shouldn't make any difference; resize is defined in terms
of insert and erase. But it is usually preferable to use the
standard idiom, so that it can easily be recognized. And of
course, the erase-remove idiom will work with any sequence
container, and not just those which support resize. (All of
the standard containers do seem to support resize, but it
doesn't seem to be a requirement. So it might not be available
on user defined containers, even though they support all
required operations.)
In terms of performance: the resize must do one additional
test, to determine whether it is erasing or inserting, but
I can't imagine this making a significant impact.
I think erase in erase(first,last) guarantees that no elements before first are accessed or modified, while resize only guarantees this when no reallocation happens because of the resize.
Edit: as pointed out by others, such a reallocation will never happen, so there's no difference
Related
Consider the following snippet (saw something analogous to this in a large simulation code)
std::vector<int> v1{1,2,3,4,5,6,7};
std::vector<int> v2;
std::move(v1.begin() + 2, v1.end(), back_inserter(v2));
Here, I am moving a range of elements from v1 to v2, but is there any particular advantage to doing this vs. copying? I do not actually see what the advantage of the move here would be since it's operating on a range of ints. In fact, I do not believe any move is occurring since we are dealing with POD types.
If we instead wanted to transfer the entire v1 to v2, then we could do:
v2 = std::move(v1);
The cast here would allow v2 to now own the pointer to the contiguous range of memory previously owned by v1, thus avoiding a copy.
But in the former move of a range of elements, I do not see the usefulness.
Here, I am moving a range of elements from v1 to v2, but is there any
particular advantage to doing this vs. copying?
No. Here is all happened just a range coping, because your usage of std::move for primitive types just do coping. Therefore it does the same as simple if you would have:
std::vector<int> v2{v1.begin() + 2, v1.end()};
Therefore you are correct about the findings. However, it is called fundamental types/ primitive types, not PODs.
But in the former move of a range of elements, I don't see the usefulness.
Consider the case of std::vector</*expensive copy type*/>, in which it makes sense to have a move of the underlying range elements, whenever is possible.
For instance consider the std::vector<std::string> case
std::vector<std::string> v1{ "1","2","3","4","5","6","7" };
std::vector<std::string> v2;
// reserve memory for unwanted reallocations
v2.reserve(std::distance(v1.begin() + 2, v1.end()));
// moves the string element in the range
std::move(v1.begin() + 2, v1.end(), back_inserter(v2));
// v1 now: 1 2
// v2 now: 3 4 5 6 7
(See a demo here)
As a side note, instead of std::move the range in a separate line, for iterators, one could also use std::make_move_iterator, to do the range move construction while declaration (if make sence).
#include <iterator> // std::make_move_iterator
std::vector<std::string> v1{ "1","2","3","4","5","6","7" };
std::vector<std::string> v2{ std::make_move_iterator(v1.begin() + 2),
std::make_move_iterator(v1.end()) };
Suppose I want to get the index of the lower_bound of a value in a set and if i type
cout<<set.lower_bound(number)-set.begin()<<endl;
It is showing an error: no match for ‘operator-’
The same goes for maps as well,
However for arrays and vectors if i use
lower_bound(begin,end,val)-begin
it is showing the index
Why is that?
Yes, this because the operator - is not defined for the iterators of std::sets (bidirectional iterators) while it's defined for the arrays iterators (random access iterators).
Instead, you can use std::distance(), as follows
int main()
{
std::set<int> set {1, 2, 4, 5, 6};
int number = 3;
std::cout<<std::distance(set.begin(), set.lower_bound(number))<<std::endl;
}
And note that your sets will be ordered. I don't know what u expect.
And as john said there might be a design flaw. maybe you choose the wrong container for your purpose.
Is there any way to access the iterator in order to find the index of the element we are processing when using std::for_each() from the algorithm header? This could be useful in cases that execution policy is required.
Consider the following example (mutex and .. removed for simplicity) in the second std::for_each() where execution policy std::par_unseq is used, i++ could not be used on pain of undefined behaviour. So is there a way to access the iterator and find the index without having to pair the index to vec2 elements?
Also looking for a general solution for all containers?
vector<int> vec1{1, 4, 5, 6, 9, 0, 3, 9};
vector<int> vec2{1, 5, 2, 3};
vector<int> vec3(4), vec4(4);
size_t i = 0;
for_each(vec2.begin(), vec2.end(), [&vec1, &vec3, &i](const auto& e) {
vec3[i++] = vec1[e];
});
for_each(execution::par_unseq, vec2.begin(), vec2.end(), [&vec1, &vec4](const auto& e) {
vec4[distance(vec2.begin(), current_iterator)] = vec1[e];
});
std::vector has contiguous memory so you can use pointers(and calculate their difference).
That being said I do not understand your original problem or motivation so you may want to consider recreating this question with more details or editing it.
I understand that you do not want to use size_t i = 0; kind of iterator for obvious reasons and I would also not recommend that. Look for Iterator validity section of distance before using it with any container.
When you use for_each with std::par_unseq then it will be totally random. In fact in my test your first loop is also copying in random order. {4,0,5,6} instead of {1,4,5,6}.
I would suggest you to use a sequential container and divide it to ranges so different ranges can be parallelized sequentially or design your own non-sequential container which can be divided with some logic and used in parallel.
I want to traverse a list in C++ but only till fifth from last not till the end.
But I see that there is no "-" operator defined so that I could use
list<>::iterator j=i-5;
I can do it using size() function somehow keeping counts etc but is there any other direct way?
Count is the only practical way that may not involve effectively traversing the list in some way.
auto myEnd = std::advance(myList.end(),-5)
but this will just traverse the last five list elements to get to your desired point, so its no faster or more elegant than most other solutions. However, using an integer loop does require keeping both an integer count and an iterator, this really only requires the iterator so in that regard it may be nicer.
If your <list> has an O(1) count, and the distance back from end is large, use an integer loop, else the above is nice.
List doesn't support random access iterators. You can use reverse iterator and counter.
You could use std::advance to get the iterator to the fifth from last.
The list has bidirectional iterator. So that to get the fifth iterator from the end iterator you should 5 times apply operation -- that is defined for bidirectional iterators. The C++ Standard provides two functions that perform this task. The first one that appeared in C++ 2003 is std::advance. The second one that appeared in C++ 2011 is std::prev. It is simpler to use the second function, std::prev, because it returns the needed iterator. For example
std::list<int> l = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
std::copy( l.begin(), std::prev( l.end(), 5 ), std::ostream_iterator<int>( std::cout, " " ) );
In addition to the available answers, I'd recommend sticking to a standard algorithm for traversing the list rather than dealing with iterators directly; if you can avoid it.
For example:
auto l = list<int>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
for_each(begin(l), prev(end(l), 5), [](const int& i) {
cout << i << endl;
});
http://ideone.com/6wNuMP
Is there an one-liner that converts a list<T> to vector<T>?
A google search returns me a lot of results that use manual, lengthy conversion, which make me puke. Should we go to that much trouble to do something as simple as a list-to-vector conversion?
You can only create a new vector with all the elements from the list:
std::vector<T> v{ std::begin(l), std::end(l) };
where l is a std::list<T>. This will copy all elements from the list to the vector.
Since C++11 this can be made more efficient if you don't need the original list anymore. Instead of copying, you can move all elements into the vector:
std::vector<T> v{ std::make_move_iterator(std::begin(l)),
std::make_move_iterator(std::end(l)) };
In C++23, the correct answer is:
std::vector<T> = l | std::ranges::to<std::vector>();
This will be more efficient than what I propose below.
The accepted answer of:
std::vector<T> v(std::begin(l), std::end(l));
is certainly correct, but it's (quite unfortunately) not optimal given the recent change in requirement that std::list::size() be O(1). If you have a conforming implementation of std::list (which, for instance, gcc didn't have until 5+), then the following is quite a bit faster (on the order of 50% once we get to 50+ elements):
std::vector<T> v;
v.reserve(l.size());
std::copy(std::begin(l), std::end(l), std::back_inserter(v));
It's not a one liner, but you could always wrap it in one.
How about this?
list<T> li;
vector<T> vi;
copy(li.begin(),li.end(),back_inserter(vi));
Another easy way:
list<int> l {1, 2, 3, 4};
vector<int> v(l.begin(), l.end());
Although this thread is already old, as "append()" is not available anymore, I wanted to show the newer emplace_back one-liner:
v.emplace_back(l.begin(), l.end());
But this way every element will be re-constructed, so it may not be the fastest solution!