I have a for loop in the below code and I would like to implement it using std::for_each. I have implemented it. Could someone please tell me if that is the best way to do it using std::for_each? If not, could you please suggest the right one?
#include <vector>
#include <cstdint>
#include <string>
#include <algorithm>
#include <iostream>
#include <sstream>
int main()
{
std::vector<std::uint32_t> nums{3, 4, 2, 8, 15};
std::stringstream list1;
for (auto n : nums)
{
list1 << n<<",";
}
//Is this the right way to do using std::for_each so that above for loop can be done in 1 line??
std::for_each(nums.begin(),nums.end(),[&list1](std::uint32_t n){ list1 << n << ","; });
}
Yes, your use of for_each is a reasonable analog of the preceding loop.
I feel obliged to point out, however, that I find for_each probably the least useful algorithm in the library. From what I've seen, using it generally indicates that you're still basically thinking in terms of loops, and just changing the syntax you use for those loops. I also think that range-based for loops have probably eliminated at least 90% of the (already few) legitimate uses there used to be for for_each.
In this case, your code is really imitating using std::copy with an std::ostream_iterator:
std::copy(nums.begin(), nums.end(),
std::ostream_iterator<std::uint32_t>(std::cout, ","));
Even this, however, is clumsy enough that I think it's open to question whether it's really an improvement over a range-based for loop.
Why don't you just test it out?
auto vs std::for_each
As you can see the assembly output is the same for both. It just doesn't make any difference for your example.
If you want to copy the data from one thing to another you can use std::copy
int main()
{
std::vector<std::uint32_t> nums{3, 4, 2, 8, 15};
std::stringstream list1;
std::copy(nums.begin(), nums.end(),std::ostream_iterator<std::uint32_t>(list1,","));
std::cout << list1.str();
}
Live Example
This will end the stream with a , but that is the same thing you get in you code.
If you do not want this then you should look at Pretty-print C++ STL containers
Yes, that is right. There is no need for the reference in (std::uint32_t &n) if you had performance as the motive.
Related
Say I have an std::list<int> lst and some std::list<int>::iterator it for iterating through the list. And depended to value of the it I want to use it + 1 or it - 1 in my code. Is there some good way to do that like next(), prev() (I couldn't find such things in stl documentation)? Or should I copy the it each time and increment(decrement) the copy?
Yes, since C++11 there are the two methods you are looking for called std::prev and std::next. You can find them in the iterator library.
Example from cppreference.com
#include <iostream>
#include <iterator>
#include <list>
int main()
{
std::list<int> v{ 3, 1, 4 };
auto it = v.begin();
auto nx = std::next(it, 2);
std::cout << *it << ' ' << *nx << '\n';
}
Output:
3 4
Copying and incrementing/decrementing the copy is the only way it can be done.
You can write wrapper functions to hide it (and as mentioned in answers, C++11 has std::prev/std::next which do just that (and Boost defines similar functions). But they are wrappers around this "copy and increment" operation, so you don't have to worry that you're doing it "wrong".
A simple precanned solution are prior and next from Boost.utility. They take advantage of operator-- and operator++ but don't require you to create a temporary.
The task of removing elements with a certain property from a std::vector or other container lends itself to a functional style implementation: Why bother with loops, memory deallocation and moving data around correctly?
However the standard way of doing this in C++ seems to be the following idiom:
std::vector<int> ints;
...
ints.erase(
std::remove_if(ints.begin(),
ints.end(),
[](int x){return x < 0;}),
ints.end());
This example removes all elements less than zero from an integer vector.
I find it not only ugly but also easy to use incorrectly. It is clear that std::remove_if cannot change the size of the vector (as its name would suggest) because it only gets iterators passed. But many developers, including myself, don't get that in the beginning.
So is there a safer and hopefully more elegant way to achieve this? If not, why?
I find it not only ugly but also easy to use incorrectly.
Don't worry, we all did at the start.
It is clear that std::remove_if cannot change the size of the vector (as its name would suggest) because it only gets iterators passed. But many developers, including myself, don't get that in the beginning.
Same. It confuses everyone. It probably shouldn't have been called remove_if all those years ago. Hindsight, eh?
So is there a safer and hopefully more elegant way to achieve this?
No
If not, why?
Because this is the safest, most elegant way that preserves performance when deleting items from a container in which deleting an item invalidates iterators.
anticipating:
Anything I can do?
Yes, wrap this idiom into a function
template<class Container, class F>
auto erase_where(Container& c, F&& f)
{
return c.erase(std::remove_if(c.begin(),
c.end(),
std::forward<F>(f)),
c.end());
}
The call in the motivating example then becomes:
auto is_negative = [](int x){return x < 0;};
erase_where(ints, is_negative);
or
erase_where(ints, [](int x){return x < 0;});
This will become available in a C++17-ready compiler soon through the std::experimental::erase_if algorithm:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
#include <experimental/vector>
int main()
{
std::vector<int> ints { -1, 0, 1 };
std::experimental::erase_if(ints, [](int x){
return x < 0;
});
std::copy(ints.begin(), ints.end(), std::ostream_iterator<int>(std::cout, ","));
}
Live Example that prints 0,1
When I uncomment the commented line with std::transform then the above for_each won't print anything. The for_each below also does not print anything. I thought the code would take the elements from v, increase them and insert them into v2.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void print(const int& what){
cout<<what<<" ";
}
int change(const int& from){
return from+1;
}
int main() {
vector<int> v(5,10);
vector<int> v2;
for_each(v.begin(),v.end(),print);
//transform(v.begin(),v.end(),v2.begin(),change);
for_each(v2.begin(),v2.end(),print);
return 0;
}
Your second collection is empty -- to insert items into it, you'd want to use a std;:back_inserter:
transform(v.begin(), v.end(), back_inserter(v2), change);
Note, however, that for_each isn't really the optimal choice here either. If you're going to use a standard algorithm, I'd recommend copying to an ostream_iterator:
copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
transform(v.begin(), v.end(), back_inserter(v2));
copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
If all you really want to do is add one to each item in the input, you may find it easier to use something like std::plus instead of writing that code for yourself (or, if you have C++11 available, you could use a lambda).
To answer the question you actually asked (why none of it really works when you do your transform as it was): you had undefined behavior attempting to access the vector outside its current bounds. As such, any behavior is allowed. It's often a little hard to see how UB later in a program could affect behavior of code before the UB has actually been invoked, but the standard is quite explicit in allowing that. Some compilers take advantage of this to enable optimizations (for example) that wouldn't be (or might not be) possible otherwise.
The destination range for std::transform must be large enough to hold the results. Your v2 is an empty vector. You could call v2.resize() before calling std::transform or use back_inserter like so:
transform(v.begin(),v.end(),back_inserter(v2),change);
Say I have an std::list<int> lst and some std::list<int>::iterator it for iterating through the list. And depended to value of the it I want to use it + 1 or it - 1 in my code. Is there some good way to do that like next(), prev() (I couldn't find such things in stl documentation)? Or should I copy the it each time and increment(decrement) the copy?
Yes, since C++11 there are the two methods you are looking for called std::prev and std::next. You can find them in the iterator library.
Example from cppreference.com
#include <iostream>
#include <iterator>
#include <list>
int main()
{
std::list<int> v{ 3, 1, 4 };
auto it = v.begin();
auto nx = std::next(it, 2);
std::cout << *it << ' ' << *nx << '\n';
}
Output:
3 4
Copying and incrementing/decrementing the copy is the only way it can be done.
You can write wrapper functions to hide it (and as mentioned in answers, C++11 has std::prev/std::next which do just that (and Boost defines similar functions). But they are wrappers around this "copy and increment" operation, so you don't have to worry that you're doing it "wrong".
A simple precanned solution are prior and next from Boost.utility. They take advantage of operator-- and operator++ but don't require you to create a temporary.
I have two sets.they have some common elements(sets have strings as thier elements)
like :
set1 has elements
"1-2","1-1","3-4"
set2 has elements
"1-2","1-3","3-4"
i want take out the values "1-1" into one set
and value "1-3" into another.
i know set_difference will do the job for me.But some how i am facing some problems with set_ifference.please check here
Is there any alternative to using set_difference achieving the same reults?
The alternative would be to roll your own, as Kerrek SB did in his answer to your question.
That said, it would be far better to understand and to solve the problem you have with std::set_difference(), rather than working around it.
For instance, were I getting long compiler errors involving templates on the line containing set_difference, I would break this up into a small series of separate, simple statements, which will make pinpointing the error much easier:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <set>
#include <string>
int main()
{
typedef std::set<std::string> set_of_strings;
set_of_strings s1, s2, result;
s1.insert("1-2");
s1.insert("1-1");
s1.insert("3-4");
s2.insert("1-2");
s2.insert("1-3");
s2.insert("3-4");
// Temporary variables for debugging only
set_of_strings::iterator s1_begin = s1.begin();
set_of_strings::iterator s1_end = s1.end();
set_of_strings::iterator s2_begin = s2.begin();
set_of_strings::iterator s2_end = s2.end();
set_of_strings::iterator result_end = result.end();
std::insert_iterator<set_of_strings> result_inserter = std::inserter(result, result_end);
std::set_difference(s1_begin, s1_end,
s2_begin, s2_end,
result_inserter);
std::copy(result.begin(),
result.end(),
std::ostream_iterator<std::string>(std::cout, "\n"));
}
The compiler would then check that each of set_difference's five parameters is of the type that it expects and would allow me to see quite quickly which of them is causing the issue because they're all declared in separate statements.
Once I'd solved the issue, I'd refactor to remove the unnecessary variables, of course.