Template function taking iterators as arguments - c++

Exercise: Write a function template that takes a pair of values that
represent iterators of unknow type. Find the value that
occurs most frequently in the sequence
My work:
template <typename Iterator>
typename std::iterator_traits<Iterator>::value_type
funkcija(Iterator begin, Iterator end)
{
typename std::iterator_traits<Iterator>::value_type Frequency;
typename std::iterator_traits<Iterator>::value_type frequencyTemp;
typename std::iterator_traits<Iterator>::value_type frequencyHighest = 0;
for ( Iterator tempIter = begin; tempIter != end; ++tempIter)
{
frequencyTemp = count (begin, end, *tempIter);
if (frequencyTemp > frequencyHighest)
{
frequencyHighest = frequencyTemp;
Frequency = *tempIter;
}
}
return Frequency;
}
int main()
{
std::vector<std::string> words;
words.push_back("ada");
words.push_back("dada");
words.push_back("mada");
words.push_back("ada");
words.push_back("dada");
words.push_back("ada");
words.push_back("kada");
std::vector<std::string>::iterator first = words.begin();
std::vector<std::string>::iterator last = words.end();
std::cout << "Most frequent value is " << funkcija(first,
last) << std::endl;
return 0;
}
It compiles fine, but when try to run it I got error message that
Debug Assertion Failed!
Expression: invalid null pointer.
I would appreciate if someone could tell me what I did wrong.

Check the types of your variables: some of them are wrong.
The specific thing that's triggering the message is that you are trying to initialize the string frequencyHighest with a null pointer, as specified by the literal 0. (i.e. it's trying to use the constructor that takes a C-style string and copies it into the newly constructed std::string)
When your program is crashing and you don't know what's causing it, one easy thing you can often do is simply keep removing parts of your program until it stops crashing; then you know the crash is probably related to the parts you just removed.
You can usually pin the cause down very narrowly this way -- and even if you can't, it gives you a much better sample program to post when you're asking for help.
Although as the comments said, a debugger would have made it even more plain.

Related

Why boost filter_iterator has weird make_filter_iterator function?

after some pain I managed to hack together this minimal example of boost filter_iterator
using namespace std;
std::function<bool(uint32_t)> stlfunc= [](uint32_t n){return n%3==0;};
int main()
{
vector<uint32_t> numbers{11,22,33,44,55,66,77,3,6,9};
auto start = boost::make_filter_iterator(stlfunc, numbers.begin(), numbers.end());
auto end = boost::make_filter_iterator(stlfunc, numbers.end() , numbers.end());
auto elem = std::max_element(start,end);
cout << *elem;
}
It works nice, but I wonder why the make_filter_iterator takes numbers.end()?
I might be wrong to use it that way, I guestimated it from the C array example:
http://www.boost.org/doc/libs/1_53_0/libs/iterator/example/filter_iterator_example.cpp
That is explained in the docs:
When skipping over elements, it is necessary for the filter adaptor to
know when to stop so as to avoid going past the end of the underlying
range. A filter iterator is therefore constructed with pair of
iterators indicating the range of elements in the unfiltered sequence
to be traversed.
From the source below you can see the always check if they have reached the end in satisfy_predicate:
void increment()
{
++(this->base_reference());
satisfy_predicate();
}
void satisfy_predicate()
{
while (this->base() != this->m_end && !this->m_predicate(*this->base()))
++(this->base_reference());
}
Also, as pointed out by Alex Chamberlain, the
constructors make it optional when passing the end iterator, for example: filter_iterator(Iterator x, Iterator end = Iterator()); (provided it is default constructible). So, you could omit numbers.end() from your code when constructing the end iterator.
If you look at the declaration of your make_filter_iterator template, you see it looks like this:
template <class Predicate, class Iterator>
filter_iterator<Predicate,Iterator>
make_filter_iterator(Predicate f, Iterator x, Iterator end = Iterator());
Specifically you see that the last parameter is a default parameter, and it's set to Iterator() which would mean it's default contructed and for some types of iterator it behaves like actual end() iterator, which points one past the end of any array, ie it points to garbage.
Most container types do require an actual end() iterator to be passed.

Iterating over Boost fusion::vector

I'm trying to iterate over a boost::fusion vector using:
typedef typename fusion::result_of::begin<T>::type t_iter;
std::cout << distance(begin(t), end(t)) << std::endl;
for(t_iter it = begin(t); it != end(t); next(it)){
std::cout<<deref(it)<<std::endl;
}
The distance cout statement gives me a finite length (2), however the loop seems to run indefinitely.
Any advice much appreciated!
You can't just iterate a Fusion vector like that, the type for each iterator may be different than the previous one (and usually is). I guess that's why you don't have it = next(it) in your code, it would give a compilation error.
You could use boost::fusion::for_each for this, together with a function object that prints each element to the standard output:
struct print
{
template< typename T >
void operator()( T& v ) const
{
std::cout << v;
}
};
...
boost::fusion::for_each( t, print() );
fusion is a wonderful library, and you should now that it is really different from what you use in every day C++ programs in multiple ways, it merge the power of compile time meta programming with runtime, for that you should now that there is no type that can handle all items in a fusion container. What this means? it means that result_of::begin<T>::type is not always a match of next(it) so you can't use fusion iterators in a for like that.
The obvious problem in your code is that you ignore return value of next and it will cause your code to run forever but you can't use it in it = next(it), since their type may vary!!
So what you should do?? You should use boost::fusion::for_each for that purpose
next doesn't actually advance the iterator, it just returns the next one.
This can be seen in the docs, as the function next takes a constant argument, meaning it can't possibly actually modify the iterator:
template<
typename I
>
typename result_of::next<I>::type next(I const& i);
^^^^^
The problem is that inside the loop you are dereferencing your iterator. When you apply next on it, it means nothing and that's why your loop runs forever.

Error when using set_union and set_intersection

I have two sets and I'm trying to do a union (I get the same error when doing an intersection). Here is the error:
error C3892: 'std::_Tree_const_iterator<_Mytree>::operator *' : you cannot assign to a variable that is const
Code snippet(if I comment out the line with the --> then the code compiles and my work around way of doing the union works fine):
set<Line *>::iterator it;
set<Line *> * newSet = new set<Line *>();
leftLines = pLeft->getSet();
rightLines = pRight->getSet();
-->it = set_union(leftLines->begin(),leftLines->end(),rightLines->begin(), rightLines->end(), newSet->begin());
for(it = leftLines->begin(); it != leftLines->end(); it++)
{
newSet->insert(*it);
}
for(it = rightLines->begin(); it != rightLines->end(); it++)
{
newSet->insert(*it);
}
it = newSet->begin();
while(it != newSet->end())
{
result->insert(*it);
it++;
}
I'm sure this is something silly but I'm kind of lost. I think that code snippet should be enough but I can provide whatever else is needed. Thanks.
This is C++, not Java [edit: or .NET]. You almost certainly want to replace (for example):
set<Line *> * newSet = new set<Line *>();
with just:
set<Line *> newSet;
...or, better still, probably just:
set<Line> newSet;
Although it's impossible to say for certain based on the code you've posted, there's a pretty fair chance that your left and right shouldn't be dealing in pointers either -- if they're going to do anything of the sort, a reference probably makes more sense (though, as I said, based on just what you've posted, it's impossible to say for sure).
Once you've done that, you run into a minor problem: a "normal" iterator over a set (or multiset, map or multimap) is really a const_iterator. Once you insert something into an associative container, you're not allowed to change it because that could destroy the collection's invariant (being sorted). If you want to change an existing item, you need to delete if from the contain, make the change, and insert the changed object back into the container. In your case, you're just inserting new items, so you want an insert_iterator.
Since you're not planning on modifying either left or right, you might as well treat them as const as well:
std::set_union(left.cbegin(), left.cend(),
right.cbegin(), right.cend(),
std::inserter(newSet, newSet.end()));
If you decide to simulate set_union on your own, you can do something like this:
std::set<Line> newSet(left.cbegin(), left.cend());
std::copy(right.cbegin(), right.cend(), std::inserter(newSet, newSet.end()));
Edit:
Instead of passing around pointers to containers, you normally want to pass around iterators into the containers. For example, to print out the contents, you apparently now have something like:
void print_data(std::vector<Line *> const *data) {
for (int i=0; i<data->size(); i++)
std::cout << *(*data)[i] << "\n";
}
It probably has more formatting and such, but for the moment we'll ignore those details and assume it's this simple. To write the data directly from a container of your choice, you normally want a template that will accept iterators of an arbitrary type:
template <class inIt>
void print_data(inIt begin, inIt end) {
while (begin != end)
std::cout << *begin++ << '\n';
}
We can, however, go a step further than that, and specify the output as an iterator as well:
template <class inIt, class outIt>
void print_data(inIt begin, inIt end, outIt dest) {
while (begin != end) {
*dest++ = *begin++;
*dest++ = '\n';
}
}
You could go one more step, and allow the user to specify the delimiter to be used between the items, instead of always using '\n', but at that point, you'd just be duplicating something what's already in the standard library -- a combination of std::copy and an std::ostream_iterator, which is how you probably want to deal with this in reality:
std::copy(newSet.begin(), newSet.end(),
std::ostream_iterator<Line>(std::cout, "\n"));
Note, however, that as far as the standard library cares, an ostream_iterator is just another iterator. If you're just going to print out the union of left and right, you can skip even creating a set to hold that union, and just print it out directly:
std::set_union(left.cbegin(), left.cend(),
right.cbegin(), right.cend(),
std::ostream_iterator<Line>(std::cout, "\n"));
The fact that an ostream_iterator writes to a file instead of putting things into a normal collection is entirely irrelevant to the standard library. It has a few classes of iterators, and can write output to any iterator that models the correct class.
Now, I may be jumping the gun, so to speak -- maybe need to do other processing on the data before you write it to the console. My point isn't that you necessarily have to write the union directly to standard output, but just that you don't necessarily have to write it to some other collection before you print it out.
set iterators aren't output iterators. Use this:
set_union(leftLines->begin(),leftLines->end(),rightLines->begin(), rightLines->end(), inserter(*newSet, newSet->begin()));
Also, why're you filling newSet? Leave it as is after the union/intersection or the union/intersection will be pointless.
set<Line *>::iterator it;
set<Line *> newSet; // No need to `new` this
leftLines = pLeft->getSet();
rightLines = pRight->getSet();
set_union(leftLines->begin(),leftLines->end(),rightLines->begin(), rightLines->end(), inserter(newSet, newSet.begin()));
// Assuming you really need the below code - you could likely just make an inserter directly on `result` instead of the copying.
it = newSet.begin();
while(it != newSet.end())
{
result->insert(*it);
it++;
}

Vector iterators in for loops, return statements, warning, c++

I have three questions regarding a homework assignment for C++. The goal was to create a simple palindrome method. Here is my template for that:
#ifndef PALINDROME_H
#define PALINDROME_H
#include <vector>
#include <iostream>
#include <cmath>
template <class T>
static bool palindrome(const std::vector<T> &input)
{
std::vector<T>::const_iterator it = input.begin();
std::vector<T>::const_reverse_iterator rit = input.rbegin();
for (int i = 0; i < input.size()/2; i++, it++, rit++)
{
if (!(*it == *rit)) {
return false;
}
}
return true;
}
template <class T>
static void showVector(const std::vector<T> &input)
{
for (std::vector<T>::const_iterator it = input.begin(); it != input.end(); it++) {
std::cout << *it << " ";
}
}
#endif
Regarding the above code, can you have more than one iterator declared in the first part of the for loop? I tried defining both the "it" and "rit" in the palindrome() method, and I kept on getting an error about needing a "," before rit. But when I cut and paste outside the for loop, no errors from the compiler. (I'm using VS 2008).
Second question, I pretty much just brain farted on this one. But is the way I have my return statements in the palindrome() method ok? In my head, I think it works like, once the *it and *rit do not equal each other, then the function returns false, and the method exits at this point. Otherwise if it goes all the way through the for loop, then it returns true at the end. I totally brain farted on how return statements work in if blocks and I tried looking up a good example in my book and I couldn't find one.
Finally, I get this warnings:
\palindrome.h(14) : warning C4018: '<' : signed/unsigned mismatch
Now is that because I run my for loop until (i < input.size()/2) and the compiler is telling me that input can be negative? Thanks!
Are iterators a requirement of the homework assignment? This task can be reduced to a call to std::equal:
template <class T>
bool palindrome(const std::vector<T> &input)
{
return equal(input.begin(), input.begin()+input.size()/2, input.rbegin());
}
can you have more than one iterator declared in the first part of the for loop?
Yes, but they both have to be of the same type, so you can't declare both a const_iterator and a const_reverse_iterator.
is the way I have my return statements in the palindrome() method ok?
Yes, though why not just compare *it != *rit?
palindrome.h(14) : warning C4018: '<' : signed/unsigned mismatch
i is signed; std::vector::size() returns an unsigned value. If i was unsigned, you would not get this warning.
As a suggestion, though: it might be simpler to use two forward iterators. Initialize one to .begin() and the other to .end() - 1. You can then increment the first and decrement the second and your loop test simply becomes it1 < it2. Something like the following (completely untested) for-loop:
for (iterator it1(v.begin()), it2(v.end() - 1); it1 < it2; ++it1, --it2)
This way you no longer need the separate i counter and comparisons; everything is done with iterators.
The for loop works for me when iterators are of the same type, I haven't figured out other way yet - apart from initializing them outside like what you did:
typedef vector<char>::const_iterator IT;
for (IT it(vchars.begin()), end(vchars.end()); it != end; ++it)
{
cout << *it << endl;
}
Regarding the return statement, your reasoning is correct but you start with those 2 iterators not being the same, one starts from front the other from the end. So on the first iteration they are not equal and you return false - I believe.
And last, the warning points to the fact that size() returns unsigned type (size can't be negative) but you are compare with signed value i, which in most cases is not a real problem - but to be neat you can declare your i as unsigned.
This will fix that:
for (unsigned int i = 0; i < input.size()/2; ...)

Transforming multiple iterator elements

My problem is more complex than this, so I've narrowed it down to a very simple example that would show me enough to know how to handle the rest.
Say I have an input iterator. I want make a new input iterator derived from it, where each element is the combination of multiple sequential elements of the original input with the following pattern. The run length is encoded in the input sequence.
Input:
{ 1 1 2 3 4 4 6 7 8 9 ... }
Output:
{ (1) (3+4) (6+7+8+9) ... }
I was thinking a function like this could process a single element and increment the input begin iterator (passed by reference). There are a few questions in my comments, plus I'd like to know if there's a good way to do it for the entire stream of elements.
EDIT: I'm aware there's a bug in the call to std::advance where the tmp iterator is incremented to be exactly end, which would be valid for this code. Let's focus on the rest of my questions and I'll fix that. Edit 2: should be fixed now?
template<class TInputIterator, class TOutputIterator>
void process_single(TInputIterator& begin, TInputIterator end, TOutputIterator destination)
{
std::iterator_traits<TInputIterator>::value_type run_length = *begin;
++begin;
// is there a better way to specify run_length elements to accumulate() without having to call advance() here?
TInputIterator tmp(begin);
std::advance(tmp, run_length);
// Edited: this condition should work for the different kinds of iterators?
if ((end < tmp) || (std::distance(begin, tmp) != run_length))
throw std::range_error("The input sequence had too few elements.");
// std::plus is the default accumulate function
*destination = std::accumulate(begin, tmp, 0/*, std::plus<TInputIterator::value_type>()*/);
// should I use std::swap(begin, tmp) here instead?
begin = tmp;
}
Edit 3: In response to the answers, would this be better?
template<class TInputIterator, class TOutputIterator>
TInputIterator process_single(TInputIterator begin, TInputIterator end, TOutputIterator destination)
{
typedef std::iterator_traits<TInputIterator>::value_type value_type;
value_type run_length = *begin;
++begin;
value_type sum = 0;
while (run_length > 0 && begin != end)
{
sum += *begin;
++begin;
--run_length;
}
if (run_length)
{
throw std::range_error("The input sequence had too few elements.");
}
*destination = sum;
return begin;
}
template<class TInputIterator, class TOutputIterator>
void process(TInputIterator begin, TInputIterator end, TOutputIterator destination)
{
while (begin != end)
{
begin = process_single(begin, end, destination);
}
}
I would write this algorithm manually.
Firstly, the function does not accept an input iterator, because those don't support advance and distance.
Secondly, the error checking is off. If I'm not mistaken, the possibility of end < tmp means some undefined behaviour has been invoked. Imagine the container is a std::list. What would happen if you managed to advance beyong list.end()? But I think it would be undefined even with a vector or array (and MSVC++ would probably kick in with its iterator debugging before you).
So, to decode the whole sequence, I'd do something like this:
#include <iostream>
#include <algorithm>
#include <vector>
#include <stdexcept>
#include <iterator>
template <class InputIterator, class OutputIterator>
void decode(InputIterator start, InputIterator end, OutputIterator output)
{
typedef typename std::iterator_traits<InputIterator>::value_type value_type;
while (start != end)
{
value_type count = *start;
++start;
value_type result = value_type();
for (value_type i = value_type(); i != count; ++i, ++start) {
if (start == end) {
throw std::range_error("The input sequence had too few elements.");
}
result += *start;
}
*output = result;
++output;
}
}
int main()
{
try {
std::vector<int> v;
decode(std::istream_iterator<int>(std::cin), std::istream_iterator<int>(), std::back_inserter(v));
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
}
catch (const std::exception& e) {
std::cout << e.what() << '\n';
}
}
// is there a better way to specify run_length elements to accumulate() without having to call advance() here?
Not really.
// Edited: this condition should work for the different kinds of iterators?
if ((end < tmp) || (std::distance(begin, tmp) != run_length))
throw std::range_error("The input sequence had too few elements.");
The problem here is the < operator, which is only going to work for RandomAccessIterators. Why not just:
if (std::distance(tmp, end) < run_length)
?
// should I use std::swap(begin, tmp) here instead?
begin = tmp;
Nope.
EDIT: I'm aware there's a bug in the call to std::advance where the tmp iterator is incremented to be exactly end, which would be valid for this code. Let's focus on the rest of my questions and I'll fix that.
Incrementing to end is standard behavior for STL algorithms.
void process_single(TInputIterator& begin, TInputIterator end, TOutputIterator destination)
STL iterators aren't generally a good type to pass byref. Callers all too often want to preserve them after the call to your function. For example, passing byRef causes this not to compile:
std::vector<something> t;
std::vector<something> t2;
process_single(t.begin(), t.end(), std::back_inserter(t2))
(Many compilers will take it but it's not standard)
Better would be to pass the iterator byval and then return the new position at which you end your algorithm, to be more consistent with the rest of the STL. For example, see std::find().
Hope that helps....