Back_inserter or push_back - c++

Just a quick question - Which is better to use to add a string to the end of a vector<string>, back_inserter or push_back? mainly, which works faster(I'm working with a huge data, so the marginal difference is actually important) and what are the main differences?

The two are not equivalent. You use std::back_inserter for example when you need to pass an input iterator to an algorithm. std::vector<std::string>::push_back would not be an option in this case. For example
std::vector<std::string> a(100, "Hello, World");
std::vector<std::string> b;
std::copy(a.begin(), a.end(), std::back_inserter(b));

Related

Unexpected behaviour of for_each with transform

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);

adding elements of a vector to an unordered set

Is there an easy way to add all the elements of a vector to an unordered_set? They are of the same type. Right now, I am using a for loop and was wondering if there is a better way to do it
If you're constructing the unordered_set then:
std::vector<int> v;
std::unordered_set<int> s(v.begin(), v.end());
Forgive me if my syntax has any minor bugs, but you can try the std::copy function, its meant for this purpose.
std::vector<int> v;
std::unordered_set<int> s;
std::copy(v.begin(),v.end(),std::inserter(s,s.end()));

Boost binding to member function of vector

Please help me with the following code. I need to add lengths of strings to a vector. I have no idea how to achieve it with boost. My best idea so far is:
boost::bind(add2Vect, boost::ref(lengths), L::_1)
Where add2Vect is a simple function that takes a vector, a string and add the length of the string to the vector. L is just a shorthand for boost::lambda
But this solution is bad, because I have to create a discrete function. That's not what lambdas should be about.
The code:
vector<string> strings;
strings.push_back("Boost");
strings.push_back("C++");
strings.push_back("Libraries");
vector<int> lengths;
for_each(strings.begin(), strings.end(),
// add lengths of strings to the vector 'lengths'
);
for_each(lengths.begin(), lengths.end(),
cout << L::_1 << " "
);
Boost.Bind and Boost.Lambda are not the same thing. You can't use lambda placeholders in bind unless you're using boost::lambda::bind.
Here's how you do what you seem to want:
std::transform(strings.begin(), strings.end(), std::back_inserter(lengths),
boost::bind(&std::string::size, _1));
If you really MUST use for_each:
std::for_each(strings.begin(), strings.end(),
boost::bind(&std::vector<int>::push_back,
&lengths, boost::bind(&std::string::size, _1)));
But you should be using size_t rather than int.

Remove elements from a c++ vector where the removal condition is dependent on other elements

The standard way to remove certain elements from a vector in C++ is the remove/erase idiom. However, the predicate passed to remove_if only takes the vector element under consideration as an argument. Is there a good STL way to do this if the predicate is conditional on other elements of the array?
To give a concrete example, consider removing all duplicates of a number immediately following it. Here the condition for removing the n-th element is conditional on the (n-1)-th element.
Before: 11234555111333
After: 1234513
There's a standard algorithm for this. std::unique will remove the elements that are duplicates of those preceding them (actually, just like remove_if it reorganizes the container so that the elements to be removed are gathered at the end of it).
Example on a std::string for simplicity:
#include <string>
#include <iostream>
#include <algorithm>
int main()
{
std::string str = "11234555111333";
str.erase(std::unique(str.begin(), str.end()), str.end());
std::cout << str; // 1234513
}
Others mentioned std::unique already, for your specific example. Boost.Range has the adjacent_filtered adaptor, which passes both the current and the next element in the range to your predicate and is, thanks to the predicate, applicable to a larger range of problems. Boost.Range however also has the uniqued adaptor.
Another possibility would be to simply keep a reference to the range, which is easy to do with a lambda in C++11:
std::vector<T> v;
v.erase(std::remove_if(v.begin(), v.end(),
[&](T const& x){
// use v, with std::find for example
}), v.end());
In my opinion, there will be easier to use simple traversal algorithm(via for) rather then use std::bind. Of course, with std::bind you can use other functions and predicates(which depends on previous elements). But in your example, you can do it via simple std::unique.

How to construct a std::string from a std::vector<char>?

Short of (the obvious) building a C style string first then using that to create a std::string, is there a quicker/alternative/"better" way to initialize a string from a vector of chars?
Well, the best way is to use the following constructor:
template<class InputIterator> string (InputIterator begin, InputIterator end);
which would lead to something like:
std::vector<char> v;
std::string str(v.begin(), v.end());
I think you can just do
std::string s( MyVector.begin(), MyVector.end() );
where MyVector is your std::vector.
With C++11, you can do std::string(v.data()) or, if your vector does not contain a '\0' at the end, std::string(v.data(), v.size()).
std::string s(v.begin(), v.end());
Where v is pretty much anything iterable. (Specifically begin() and end() must return InputIterators.)
I like Stefan’s answer (Sep 11 ’13) but would like to make it a bit stronger:
If the vector ends with a null terminator, you should not use (v.begin(), v.end()): you should use v.data() (or &v[0] for those prior to C++17).
If v does not have a null terminator, you should use (v.begin(), v.end()).
If you use begin() and end() and the vector does have a terminating zero, you’ll end up with a string "abc\0" for example, that is of length 4, but should really be only "abc".
Just for completeness, another way is std::string(&v[0]) (although you need to ensure your string is null-terminated and std::string(v.data()) is generally to be preferred.
The difference is that you can use the former technique to pass the vector to functions that want to modify the buffer, which you cannot do with .data().
vector<char> vec;
//fill the vector;
std::string s(vec.begin(), vec.end());