Is there a noop iterator in the stl? - c++

If I wanted to copy the same value across an iterator range, I would think that it would be easy to have a noop iterator where you pass it a value, and when it is incremented, it would not move anywhere. This would allow using the existing std::copy and std::copy_if algorithms.
However, I can't seem to find such a beast. Am I going to have to roll my own?

Use std::fill or std::fill_n algorithm.
Some containers, e.g. std::vector<> and std::list<>, have a constructor with size and initializer:
std::vector<int> v(10, 42); // 42 is the initializer
v.resize(20, 42); // Initialize new elements with 42.

As far as I know there is no iterator for this but there is an algorithm. std::generate will take a range an assign a value to each element that is returned from the generator passed to it. If you want to assign everything 42 for instance that would look like
std::vector<int> vec(20);
std::generate(vec.begin(), vec.end(), []() { return 42; });
You can even get values that change like
std::vector<int> vec(20);
std::generate(vec.begin(), vec.end(), []() { static int counter = 0; ++counter; return counter * counter; });

Related

Vector passed by reference inside lambda cannot be modified even if mutable keyword is used

I am trying to populate a vector with integer values which are coming in from standard input as follows:
std::vector<int> v;
for_each(v.begin(),v.end(),([&](auto &i) mutable {cin>>i; v.push_back(i);}));
However, this statement is not working and the vector does not get filled with incoming values. Can you please suggest where I am going wrong?
Thanks
for_each iterates over v and operates on each of its elements. Since v is default-initialized, its size is empty, which means that for_each doesn't do anything.
You might want to use istream_iterator
std::vector<int> v;
std::for_each(std::istream_iterator<int>(std::cin),
std::istream_iterator<int>(),
[&](auto i) { v.push_back(i); });
// Or
std::copy(std::istream_iterator<int>(std::cin),
std::istream_iterator<int>(),
std::back_inserter(v));
which will read successive integers from std::cin and insert them into v.
std::for_each applies the function object (the lambda) on each element in the passed container. Therefore to the parameter passed to the lambda is the current elements in the vector however, your vector is empty so there's nothing to iterate over so it never runs. You are also trying to assign the value from std::cin to the element in the vector i and then push a reference to that element again to the back of the vector along with the already existing element.
So first of all, if you want to use std::for_each you need to pre-allocate the vectors memory so it has something to iterate over.
std::vector<int> v(5); ///< allocates space for 5 ints
You then can then run std::for_each and std::cin into the lambda's input parameter which is a iterator to the vector, saving the inputs to the vector.
std::vector<int> v(5);
std::for_each(v.begin(), v.end(), [](auto& i) { std::cin >> i; });
The benefit of this solution is that it will automatically terminate reading values once it has finished iterating through the vector, only reading the desired amount of values.
Links and Resources
std::for_each : cppreference

How to initialize a vector of distinct dynamically allocated addresses

Is it possible to create a std::vector<T*> vec; during initialization, such that each element of vec stores a distinct address on the heap?
Simply doing
int N = 10;
std::vector<T*> vec(N, new T)
makes all elements of vec store the same address on the heap. Of course, I could simply just do
int N = 10;
std::vector<T*> vec(N);
std::for_each(vec.begin(), vec.end(), [](auto &ptr){
ptr = new int;
});
Is there any way to do it from within the constructor call?
Constructors that fill values into the vector all create duplicates of a single value, so they wont work in this case.
You can do a little better than std::for_each though. Since you want each element in the vector filled in with the result of a function, std::generate (or std::generate_n) is clearly a better fit:
std::vector<T *> vec(N);
std::generate(vec.begin(), vec.end(), [] { return new int; });
That said, a vector of raw pointers is most likely a mistake, so I'd recommend exploring other options.

How do I obtain the subset of a unique-ptrs in a vector, which satisfy a predicate?

I have a vector of std::unique_ptr<Foo> objects. I want to get a collection of all vector items that match some condition.
I see the std functions but they all seem to test for a predicate (and return bool) or return a single element.
Is there a built-in mechanism to get a collection that's a subset of a vector? If not, is there a way to construct an iterator that tests items against an arbitrary predicate (to identify ones that meet my condition) and a mechanism to return all items that meet that predicate?
Be warned, since you've got a vector of unique_ptr, those elements can only be moved around, i.e. once you have got the subset, the original vector will not be the same anymore.
The least destructive method is to use std::stable_partition to divide the vector into two groups, while keeping everything in the same vector:
auto sep = std::stable_partition(vec.begin(), vec.end(), [](const auto& foo) {
return foo->is_good();
});
// the part `vec.begin() .. sep` contains all "good" foos.
// the part `sep .. vec.end()` contains all "bad" foos.
If order is not important, use std::partition instead. The usage is the same.
If you want to split the bad foos into another vector, you could use std::copy_if + std::make_move_iterator to move the objects out. Note that this will leave holes everywhere. Use std::remove to clean them up.
decltype(vec) bad_vec;
std::copy_if(std::make_move_iterator(vec.begin()),
std::make_move_iterator(vec.end()),
std::back_inserter(bad_vec),
[](const auto& p) { return !p->is_good(); });
auto new_end = std::remove(vec.begin(), vec.end(), nullptr);
vec.erase(new_end, vec.end());
If you no longer care about the "bad" objects, use std::remove_if:
auto new_end = std::remove_if(vec.begin(), vec.end(), [](const auto& foo) {
return !foo->is_good();
});
vec.erase(new_end, vec.end());
// now `vec` only contains "good" foos.
If you just want to get the raw pointers, instead of the unique_ptr itself, you could use std::transform to fill up a vector<Foo*> and then remove_if to filter it... But at this point it is probably just easier to write the for loop.
std::vector<int*> good_vec;
for (const auto& foo : vec) {
if (foo->is_good()) {
good_vec.push_back(foo.get());
}
}
Since your vector holds unique_ptr's (which we don't make copies of) - I'd recommend the second option you inquired about: An iterator which only iterates those elements matching your predicate. This is exactly boost::filter_iterator.
Sort-of-an example:
bool points_to_positive(int* ptr) {
return ptr != nullptr and *ptr > 0;
}
// ...
std::vector<std::unique_ptr<int>> vec;
// ...
auto iterator = boost::make_filter_iterator(
&points_to_positive, std::begin(vec), std::end(vec)
);
if, however, you plan on making that iteration multiple times, and do not want to trade time for space, you would probably be better served by just copying out the actual pointers like in #kennytm's last suggested option.
What you asked for is std::copy_if from <algorithm>. For unique_ptr elements, which cannot be copied, this is not what you want. Sample code:
#include <algorithm>
#include <array>
#include <cstdlib>
#include <experimental/array>
#include <iostream>
#include <type_traits>
#include <vector>
using std::cout;
using std::endl;
using std::size_t;
bool is_even( const int n )
{
// True iff n is even.
return n % 2 == 0;
}
std::ostream& operator<< ( std::ostream& os, const std::vector<int>& container )
{
// Boilerplate instrumentation.
for ( const int& x : container )
os << x << ' ';
return os;
}
int main(void)
{
// Our input array, raw:
constexpr int digits[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
// The number of input elements:
constexpr size_t ndigits = std::extent<decltype(digits)>();
// Container wrapping our input array:
constexpr std::array<int, ndigits > numbers =
std::experimental::to_array(digits);
std::vector<int> even_numbers;
even_numbers.reserve(ndigits); // Upper bound on output size.
std::copy_if( numbers.cbegin(),
numbers.cend(),
std::back_inserter(even_numbers),
is_even );
even_numbers.shrink_to_fit();
// Correct output is "2 4 6 8 "
cout << even_numbers << endl;
return EXIT_SUCCESS;
}
However, your array contains unique_ptr objects, which can’t be copied. Several answers have other good suggestions to get equivalent results. If you want to copy the references meeting the requirements to a different collection, though, you could also change unique_ptr to shared_ptr or weak_ptr, which can be copied.

std::transform on a multiset giving me error C3892

I am trying to understand how the std::transform function works, but I'm having a bit of trouble with the following code. I want to take a multiset ms, add 1 to the contents of each element and store them in a new multiset msc. Here is what I have:
int op_increase(int i) { return ++i; }
int main()
{
std::multiset<int> ms = {1,1,2,2,3};
std::multiset<int> msc;
std::transform(ms.begin(), ms.end(), msc.begin(), op_increase);
return 0;
}
However I get the following error:
C3892: _Dest: you cannot assign to a variable that is const
Your code was not utilizing the correct argument to std::transform that allows insertion into an empty container. This requires using an iterator that is intelligent enough to call the appropriate function that calls the container's insert() function.
The solution is to provide std::transform the std::inserter iterator that automatically inserts into the empty multiset. Here is an example:
#include <set>
#include <algorithm>
#include <iterator>
int op_increase(int i) { return ++i; }
int main()
{
std::multiset<int> ms = {1,1,2,2,3};
std::multiset<int> msc;
std::transform(ms.begin(), ms.end(), std::inserter(msc, msc.begin()), op_increase);
// msc now contains 2,2,3,3,4
}
Note the std::inserter is used, and not merely msc.begin(). The inserter will automatically insert the items into the map.
Live Example
The problem here is that std::multiset<T>::begin() returns a std::_Tree_const_iterator type. That's why you cannot change its value. This behavior is sensible: the std::multiset, like std::set, is a sorted container typicaly implemented as a red-black tree, and thus change of a value of one element may require update of the whole data structure. If user really wants to do this, he may erase a node and add it back.
To better understand the std::transform behavior, you may use std::vector container instead of std::multiset. Cplusplus.com contains a good example of code using std::transform.
Also, as far as I understand from your code, you try to add the resulting data into the initially empty std::multiset. To achieve this functionality, you may use std::insert_iterator (Cplusplus.com), like this:
int op_increase(int i) { return ++i; }
int main()
{
std::multiset<int> ms = {1,1,2,2,3};
std::multiset<int> msc;
std::transform(ms.begin(), ms.end(), inserter(msc, msc.begin()), op_increase);
return 0;
}

Initialize vector of structures

Let's I have
struct Vector {
float i,j,k;
}
I want to zero all elements of vec declared below (i,j,k=0)
std::vector <Vector> vec;
vec.resize(num,0);
I don't want to use reserve() and then push_back() zeroes one by one.
Another thing is, after succesfully initializing vec, I want to set all members of vec to zero again after it is manipulated. Is there something like memset for vectors?
EDIT:
I compared all of the methods in Mike Seymour's and Xeo's answers and as a result
size_t size = vec.size();
vec.clear();
vec.resize(size); is the fastest if they are repeated frequently in a loop.
That's very simple:
vec.resize(num);
or initialise it with the required size:
std::vector<Vector> vec(num);
Both the constructor and resize will fill new elements with value-initialised objects. A value-initialised object of a type with no default constructor (such as your Vector) will have all numeric members initialised to zero.
To reset everything to zero, either
size_t size = vec.size();
vec.clear();
vec.resize(size);
or:
std::fill(vec.begin(), vec.end(), Vector());
or, less efficiently but with a strong exception guarantee:
std::vector<Vector>(vec.size()).swap(vec);
C++ way of setting all current elements to 0:
std::fill( vec.begin(), vec.end(), 0 );
Or, alternatively, to re-initialize to a given size:
vec.clear();
vec.resize(num, 0);
This might not be as performant as memset, but good enough for 99% of the cases.
You can just use memset, so long your Vector is a POD type:
std::vector<Vector> v(num, 0); // inital fill
// do stuff
memset(&v[0], 0, sizeof(Vector) * v.size());
Though the C++ version would be with std::fill
#include <algorithm>
std::fill(v.begin(), v.end(), 0);