I have a trouble in understanding the behaviour of transform function if used with back_inserter.
#include <algorithm>
using namespace std;
int main()
{
vector<int> a{1,2,4};
transform(begin(a), end(a), back_inserter(a), [](auto e){ cout << e << "-" ;
return e;});
return 0;
}
In the above program, I get the output as 1-0-4. I am not able to understand how this 0 is coming?
Please see live example cpp.sh/6vpzk
This code does vector::push_back while iterating over it using its iterators. vector::push_back invalidates all existing iterators causing undefined behaviour, and that is where that 0 comes from (it can be any other number, since the behaviour is undefined).
You should probably use for_each or range for loop.
Related
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;
}
I was trying to solve a problem which involved producing all the permutations of a set of numbers. The idea seemed simple enough (code below), but I keep getting segmentation faults. Can anyone tell me what I'm doing wrong?
void permute(set<int>& s, vector<int>& v) {
if(s.empty()) {
// read the permutation in v.
return;
}
set<int>::iterator i;
for(i = s.begin(); i != s.end(); i++) {
int x = *i;
s.erase(i);
v.push_back(x);
permute(s, v);
v.pop_back();
s.insert(x);
}
}
To produce all permutations in C++ use std::next_permutation. The problem here is that you cannot permutate the set, because the ordering is preset by the key comparator operator (in your case the less than operator). What you can do is store your values in a non associative container and then have a go.
#include <set>
#include <algorithm>
#include <iterator>
#include <vector>
using namespace std;
void permut(std::set<int> const &inp, std::vector<int> &all_permutations)
{
vector<int> tmp(inp.size());
copy(inp.begin(), inp.end(), tmp.begin());
vector<int> all_permutations;
do
{
copy(tmp.begin(), tmp.end(), back_inserter(all_permutations));
} while (std::next_permutation(tmp.begin(), tmp.end()));
}
The permute() function calls itself recursively while iterating over the mutable containers and making changes. This violates iterator validity promises.
You might try something based on std::next_permutation()
I have not gone into the precise behaviour you can expect from a set, but it seems pretty clear that the things you are doing inside the for loop are enough to make the iterator invalid. I would suggest redesigning things so that you have two sets, and work through one (which starts off full) while generating the permutation in the other (which starts off empty).
I wanted to use the sort() in the algorithm library in C++. I could find examples for sorting vectors only, thus I am trying to initialize a vector by an initialized array. When executing I am getting a segmentation fault and couldn't figure out what is wrong here in the code I wrote.
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int n,k,packet[1000],min=0;
scanf("%d",&n);
scanf("%d",&k);
for (int i = 0; i < n; ++i)
{
scanf("%d",&packet[i]);
cout<<i<<endl;
}
cout<<"debug";
vector<int> packets(packet,packet+n);
vector<int>::iterator start,stop;
sort(packets.begin(),packets.begin()+n);
min=*(packets.begin())- *(packets.end());
cout<<min;
for (vector<int>::iterator it=packets.begin(); it!=packets.end()-k; ++it)
{
printf("%d ",*it );
if((*(it+k) - *it)<min)
{
start=it;
stop=it+k;
}
}
printf("%d\n",*stop- *start );
return 0;
}
*(packets.end())
packets.end() returns an iterator to the element, following the last element of the vector.
Attempting to derefenrence it causes Undefined Behavior.
The comments explain that you can use sort with an array just fine (if you look at http://en.cppreference.com/w/cpp/algorithm/sort you'll see that sort takes two arguments that: -RandomIt must meet the requirements of ValueSwappable and RandomAccessIterator.. Plain pointers fulfill this requirement).
In your example, the segfault happens because you try to dereference a valid but undereferencable iterator (the iterator returned by 'end()' in: min=*(packets.begin())- *(packets.end());. Basically it returns an iterator that points to after the last element of the vector. If you want to get an iterator to the last element, you can use rbegin() but of course you need to make sure that the vector is not empty first).
You could have seen this quite easily by running your code under a debugger, you'd see that the segmentation fault had nothing to do with the call to sort
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);
i'm trying to use algorithm lib & vector lib to first copy a set of numbers from an array into a vector then printing it using iteration, where is the problem of my code?
and one thing is that i chose 2 way to do this iteration first using vec.begin() ; vec.end() method & the other one is for (i = 0 ; i < vec.capacity() ; i++)
both facing errors.
what should i do?
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
int intArray[] = {5,6,8,3,40,36,98,29,75};
vector<int> vecList(9);
//vector<int>::iterator it;
copy (intArray, intArray+9,vecList);
//for(it = vecList.begin() ; it != vecList.end() ; it++)
for (int it = 0 ; it < vecList.capacity() ; it++)
{
cout<<*it<<endl;
}
system("pause");
return 0;
}
There are several improvements possible.
You confuse iterators with indices. An iterator it is a glorified pointer into the vector, that you need to derefence by typing *it. An index i is an offset from the beginning of the vector and saying vecList[i] will give you that element.
The initialization of the vector is best done using initializer lists (C++11), rather than reading from an array.
You need to loop to vecList.size(). The capacity of the vector is the size of the allocated storage space for the elements of the vector container. Looping is best done with a ranged-for loop as shown by Kerrek SB, or a std::for_each + a lambda expression, or a regular for loop as you did. In that case however, it's best to get into the habit of doing it != vecList.end() (instead of using <) and doing ++it instead of it++.
Note that I also used auto to avoid writing the explicit iterator type. It's also a good habit to get into using auto wherever you can.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
// initialize vector with a list of elements
vector<int> vecList {5,6,8,3,40,36,98,29,75};
// loop from begin() to end() of vector, doing ++it instead of it++
for (auto it = vecList.begin(); it != vecList.end(); ++it)
{
cout<<*it<<endl;
}
// the pause command is better done by setting a breakpoint in a debugger
return 0;
}
Output on Ideone (this uses the g++ 4.5.1 compiler, it's best to upgrade to at least that version to take advantage of C++11 features).
The problem is that you're confusing indexes and iterators.
w/ index:
for (int i = 0 ; i < vecList.size() ; it++)
{
cout<<vecList[i]<<endl;
}
w/ iterators
for (std::vector<int>::const_iterator it = vecList.begin() ; i != vecList.end() ; it++)
{
cout<<*it<<endl;
}
A. you need to iterate on vecList.size() not vecList.capacity() which mean how much memory the vector is reserving for himself (not how much of it is in use).
B. you tried to use the integer index it as an iterator with the call to *it, you should check Luchian Grigore answer for the right way to do it.
This isn't an answer, but I wanted to show how modern C++ allows you to do away with lots of the brittle dependencies on details:
int intArray[] = {5,6,8,3,40,36,98,29,75};
std::vector<int> vecList(std::begin(intArray), std::end(intArray));
for (int i : vecList) { std::cout << i << std::endl; }
Using iterators and algorithms idiomatically, you can often remove any explicit mention of details such as lengths of arrays, thus making your code more robust.
Typo mistake use : copy (intArray, intArray+9,vecList.begin());
so,
#include<iostream>
#include<vector>
#include <algorithm>
using namespace std;
int main()
{
int intArray[] = {5,6,8,3,40,36,98,29,75};
vector<int> vecList(9);
vector<int>:: iterator it;
copy (intArray, intArray+9,vecList.begin());
for (it=vecList.begin();it!=vecList.end(); it++)
{
cout<<*it<<endl;
}
system("pause");
return 0;
}