I'm doing a main.cpp to test my implementation of a sparse matrix, where I create two const_iterators:
SparseMatrix<double>::const_iterator a,b;
a=mata.begin(); //mata previously created as SparseMatrix<double>
b=mata.end();
... //code goes on
The problem is that it doesn't call begin and end (it doesn't even do the initial cout), but if I create two iterators it works.
Here's how I implemented begin and end for const_iterators.
const_iterator begin() const
{
cout<<"Begin"<<endl;
int minr=minRow();
int minc=minCol(findRow(minr));
mcol * mc=findCol(findRow(minr),minc);
const_iterator x;
if(mc!=NULL)
{
T* dato=&(mc->data);
x= const_iterator(genElement(minr,minc,dato));
}
else
{
x=const_iterator(NULL);
}
x.setSM(const_cast<SparseMatrix<T>*>(this));
return x;
}
const_iterator end() const
{
cout<<"End"<<endl;
const_iterator x= const_iterator(NULL);
x.setSM(const_cast<SparseMatrix<T>*>(this));
return x;
}
A strange thing I noticed is that if I create two const_iterators inside a SparseMatrix's class method, they work.
As you say, "mata [sic] previously created as SparseMatrix<double>", but your begin and end that you show are marked const. For those const member functions to be called, the object meta must be const, else the non-const versions of begin and end will be called.
Related
#pragma once
#include <memory>
#include <vector>
#include <random>
#include <list>
class City;
class MemberReport;
class CityReport
{
private:
City* mCity;
protected:
static const int BinSize = 7;
class ReportsBin {
public:
std::shared_ptr<MemberReport> mReports[BinSize+1];
bool IsFull();
void Add(std::shared_ptr<MemberReport> report);
};
std::list<std::shared_ptr<ReportsBin>> mReportBins;
public:
explicit CityReport(City* city);
void Add(std::shared_ptr<MemberReport> report);
class Iter
{
public:
Iter(CityReport *cityReport, int pos1, int pos2) : mCityReport(cityReport), mPos1(pos1), mPos2(pos2) {}
bool operator!=(const Iter &other) const
{
return mPos1 != other.mPos1 || mPos2 != other.mPos2;
}
std::shared_ptr<MemberReport> operator *() const { return mCityReport->mReportBins[mPos1][mPos2]; }
const Iter& operator++()
{
mPos1++;
mPos2++;
return *this;
}
private:
CityReport *mCityReport;
int mPos1;
int mPos2;
};
Iter begin() { return Iter(this, 0, 0); }
Iter end() { return Iter(this, 0, 0); }
};
So I'm trying to create a custom iterator class for the class above however, I'm having trouble with the operator* and the operator++ due to the return type being stored in the form of a singly linked list inside of a list of shared pointers.
So I tried having the first parameter of the iterator constructor being ReportsBin* reportsBin although that didn't work since I need to return type std::shared_ptr<MemberReport> in the operator*. Now, I have it as CityReport* cityReport so that I can access the list of shared pointers mReportBins eventually leading to mReports. The problem is when I do mCityReport->mReportBins[mPos1][mPos2] to access mReports, I am not able to do so since you can't access lists using indices. My only other idea is to create an iterator within the operator* to iterate over the list of shared pointers of type std::list<std::shared_ptr<ReportsBin>> but I feel as though that defeats the whole purpose of the iterator class. I can't modify the CityReport class either, I can only work with the iterator class at hand.
I think using int for mPos1 is a mistake.
An iterator would be a better type in most situations. Unfortunately you make mReportBins accessible (as it is protected and not private) so depending on how you use it maybe int is better. But for argument’s sake; let's use an iterator.
While we are at it may as well use an iterator for mPos2 as it will make the logic easier (though you can use int and swap checks for end against checks against the size of the array without any major difference.
Let's address the ReportsBin type first:
class ReportsBin {
public:
// Rather than using a C-Array
// Upgrade to a std::array this makes it easier using some types.
using ReportsCont = std::array<std::shared_ptr<MemberReport>, BinSize+1>;
// We may not be upgrading this to full container status.
// But lets make accessing the members container here easier by
// providing some simple iterator accesses to the memebers.
using iterator = ReportsCont::iterator;
ReportsCont mReports;
iterator begin() {return std::begin(mReports);}
iterator end() {return std::end(mReports);}
bool IsFull();
void Add(std::shared_ptr<MemberReport> report);
};
Next lets address the container you are using to store the ReportBin. You use a std::list and I am fine with theat. But lets make accessing the type information easier by using a couple of using directives.
using Container = std::list<std::shared_ptr<ReportsBin>>;
using ContainerIter = Container::iterator;
Container mReportBins;
Now we can define the member of Iter in terms of the types we have defined that makes it easy to read and easy to modify in a single place.
class Iter // More traditionally this should be iterator
{
// STUFF
..
private:
CityReport* mCityReport;
ContainerIter mPos1;
ReportsBin::iterator mPos2;
};
This makes our dereference operator trivial.
std::shared_ptr<MemberReport> operator*() const
{
return *mPos2;
}
Constructor:
You only ever used the constructor to the first element. So why force this user to provide those 0,0. Let's remove that. Let's also not pass around raw pointers unless we really have to, so make the parameter a CityReport& so that users know it can never be null it always refers to something.
Iter(CityReport& cityReport, ContainerIter p1)
: mCityReport(&cityReport) // convert to pointer here
// Allows copying.
, mPos1(p1)
{
// We can only set mPos2 if mPos1 is dereferancable.
if (mPos1 != mCityReport->mReportBins.end()) {
mPos2 = (*mPos1)->mReports.begin();
}
}
Like the constructor, you need to take special care of the test for situations where mPos1 is no longer dereference as mPos2 is no longer valid in a test. So the comparison becomes a little more complex:
bool operator==(const Iter &other) const
{
auto end = mCityReport->mReportBins.end();
// If mPos1 and other.mPos1 are both at the end.
// then the value of mPos2 have no meaning, so don't compare.
return (mPos1 == end && other.mPos1 == end)
// Otherwise, make sure both iterators are the same.
|| (mPos1 == other.mPos1 && mPos2 == other.mPos2);
}
// Usually good to define both == and != and define them in
// terms of each other for consistency.
bool operator!=(const Iter &other) const {return !(*this == other);}
This leaves the increment:
Your increment looks strange. If you want to move diagonally across the array that seems fine. But you don't make a check to make sure the two containers are square with each other. So it looks wrong. So I have taken the liberty of redefining the increment so it goes across all elements.
const Iter& operator++()
{
// Increment mPos2 to the next element.
// Note this is fine without a test.
// It is illegal to call operator++ on an iterator where
// mPos1 is at the end.
++mPos2;
// If we reach the end of its container
// Then we need to do some extra work to move to the next
// container.
if (mPos2 == (*mPos1)->mReports.end()) {
// Increment the outer iterator.
// If we are not at the end of the container
// reset mPos2
++mPos1;
if (mPos1 != mCityReport->mReportBins.end()) {
mPos2 = (*mPos1)->mReports.begin();
}
}
return *this;
}
Now lets define begin and end.
Iter begin() { return Iter(*this, this->mReportBins.begin()); }
Iter end() { return Iter(*this, this->mReportBins.end()); }
Lets address other things you should be thinking about.
You look like you want to make this a container.
To do that you need to define a few more helper types in the container type and support a couple of other standard functions.
There are a couple of different types of container:
https://en.cppreference.com/w/cpp/container
But the basics of what you "should" support are here:
https://en.cppreference.com/w/cpp/named_req/Container
Types your container should support:
// A typical container class will define these.
using value_type = T;
using reference = T&;
using const_reference = const T&;
using iterator = <Type of Your Iterator>;
using const_iterator = const iterator;
using difference_type = std::ptrdiff_t;
using size_type = std::size_t;
// Note: You may have to customize these.
// Or explicitly not support them if that makes sense.
Your Iterator class should also define some (very similar types) types:
https://en.cppreference.com/w/cpp/iterator/iterator_traits
You can define an explicit instantiation of iterator_traits to get these types. But it is usually easier to define them in the iterator type itself.
using value_type = MemberReport;
using reference = MemberReport&;
using const_reference = const MemberReport&;
using iterator = MemberReport*;
using const_iterator = MemberReport const*;
using difference_type = std::ptrdiff_t;
using size_type = std::size_t;
I was implementing an iterator that takes another float values producing input iterator and returns true if a rising was detected. So, the iterator works effectively as a Software-ADC (Analog-Digital-Converter).
I've minimized the actual code to the following:
#include <iterator>
template<typename It>
struct ADCFilter
{
using iterator_tag = std::input_iterator_tag;
ADCFilter(const float threshold, It it)
: It_{it}, Threshold_{threshold}, LastAnalogVal_{0}
{}
bool operator*()
{
float analog_val = *It_;
// rising edge
if (analog_val >= Threshold_ && LastAnalogVal_< Threshold_)
{
LastAnalogVal_ = analog_val;
return true;
}
// no rising edge
LastAnalogVal_ = analog_val;
return false;
}
ADCFilter operator++() { ++It_; return *this; }
// Problem is here
ADCFilter operator++(int) {auto self = *this; operator++(); return self; }
private:
It It_;
float Threshold_;
float LastAnalogVal_;
};
As you can see I need to cache the last analog value.
And if somebody uses the iterator in such a way:
std::vector<float> v = {...};
auto f = ADCFilter(0.2f, v.begin());
while(true) {
std::cout << *f++; // <- post inc
}
The cached value is never stored as it's only present in the returned copy.
This problem doesn't occur though with pre increment because we are dereferencing the actual iterator and not a copy of it.
I could easily prohibit the usage of post increment operator by not implementing it, but according to https://en.cppreference.com/w/cpp/named_req/InputIterator it must be implemented for input iterators.
So, the question is how can I correctly implement a stateful input iterator that acts like a filter/mapper to another input iterator?
This can be done by reimplementing the operator so that its internal data holds just the bool value, instead of the floating point value from which the bool value is derived only when the iterator gets dereferenced.
In other words, the dereferencing iterator should simply be:
bool operator*() const // It should be const, by the way
{
return value;
}
// ...
private:
bool value;
The constructor initializes the value to false. All the code that's currently in the dereferencing operator gets basically moved into the operator++(), and its end result is an updated value. It is not necessary to hold a copy of the real value getting iterated over, the operator++ can simply compare the current value referenced by the wrapped iterator with the new value after the wrapped iterator gets incremented, and update the value.
The post-increment ++ operator remains unchanged.
I just read a chapter on templates and iterators but this still is hard to understand. basically i want to create a Set template class that accepts only one of each type of object that you put into it, implemented using a vector.
Problem is, I don't know how to write the insert function in the Set class, and the constructor in the nested iterator class. Also, most of the functions I have provided are examples from the chapter in the text, I do not even know if they are necessary or I am doing it right. Comments? Because this is a very confusing one. Here is my code:
//testSetClass.cpp
#include <iostream>
#include <vector>
using namespace std;
/****************************CLASS DEFINITION*********************************/
// -----------------------------------------
// SET
// -----------------------------------------
template <class T>
class Set
{
vector<T> theSet;
public:
Set() {}
Set(const Set& s): theSet(s.theSet){} //copy constructor
~Set(){ theSet.clear(); }
void insert(T t)
{
//insert in orderly fashion? as set class does too
//also, how do i check for duplicates?
theSet.push_back(t);
}
//nested iterator class: that supports the begin() and end() sentinel
class iterator; //declaration
friend class iterator;
class iterator //definition
{
Set<T>& s;
int index;
public:
iterator(const Set<T>& ss): s(ss), index(0){}
//to create the "end sentinel" operator:
iterator(Set<T>& ss,bool):s(ss){} //???
T operator*() {return s.theSet.at(index);} //is this right?
T operator++() //prefix form
{
return ++s.theSet.at(index);
}
T operator++(int) //postfix form
{
return s.theSet.at(index)++;
}
bool operator!=(const iterator& ri)const {return index!=ri.index;}
};
//iterators begin() and end()
iterator begin()const { return iterator (*this); }
//create the end sentinel:
iterator end() { return iterator (*this,true); } //why?
};
/*************************************END OF CLASS DEFINITIONS*********************************/
/* *****************************************************************************
* MAIN
* *****************************************************************************
*
* REMARKS:
* to test that the class works correctly.
* *****************************************************************************/
int main (int argv, char const *argc[])
{
Set<int> other;
for(int i = 0; i<10; ++i)
other.insert(i);
for(Set<int>::iterator start = other.begin(); start != other.end(); start++)
cout<<*start<<endl;
cout << "\n\nProgram ends successfully!" <<endl;
}
Use std::vector<T>::iterator for your iterator. And similar for your const_iterator.
To find, use std::equal_range. If first==second, return end().
To insert, find. If it is already there, stop. If it isn't there, insert it. The lazy way to insert it is to push back, then sort. Do it the lazy way first.
Once you have done the above, you have a working Set<T>. Test it against std::set<T> with a bunch of data. Write a bunch of unit tests to make sure this Set<T> works just like std::set<T> with regards to duplicates, ordering, finding, etc.
Now make your Set<T> more efficient. Replace that Find with a call to lower_bound and <, and insert the element where it is supposed to be instead of insert-then-sort. (It is ok that this makes no sense to you; get a working Set before even reading this, then spend some time unpacking it).
Or, make a lazy-sort Set<T> that appends blindly, and only sorts exponentially rarely on insert. On read, it either sorts, or it examines the sorted part with a binary search and the remaining (small) part with a linear search. Or somesuch.
Another improvement would be to write a manual iterator like above; one that isn't invalidated as easily as a std::vector iterator. This is ... tricky to get right.
But work on efficiency after you have correctness.
//also, how do i check for duplicates?
With theSet.find()....
iterator(Set& ss,bool):s(ss){} //???
That's not going to work. Many options, easiest being to also set index to s.theSet.size() so the existing != will work.
T operator*() {return s.theSet.at(index);} //is this right?
Nope... you need to return a T& to - rather than a copy of - the vector's element.
operator++ / operator++(int)
You need to increment the iterator (i.e. index), not increment what the iterator addresses, and should return *this (with return type iterator&). Study some iterator implementations....
iterator end() { return iterator (*this,true); } //why?
Why what? Anyway, you'd ideally provide const versions of begin() and end() that return const_iterators (which would be pretty much like iterator but only expose const T&), as well as non-const versions returning iterators: you're mixing these two ideas, with iterator begin() const.
If I have a class:
class T{
public:
int Id;
//some methods, constructor..
}
and in other class:
vector<T> collection;
and want to a write a method:
T& getValue(int Id){
//scanning the vector till i find the right value
}
The problem is that scanning the vector through iterator always give a const value so I get an error about qualifiers. So how do I get a value from a vector? but Not a const one.
EDIT: According to the Answers I tried to so something like this:
Group& Server::findGroup(unsigned int userId) const{
for(auto iterator=groups.begin();iterator!=groups.end();++iterator){
if(iterator->isInGroup(userId)){
return (*iterator);
}
}
//throw exception here
}
the definition of groups:
vector groups;
This is exactly the same example I gave at first but now T is Group.
The following code should give you a non-const iterator and work fine:
for(vector<T>::iterator i = collection.begin();
i != collection.end(); ++i) {
if(Id != i->Id)
continue;
// Matching ID! do something with *i here...
break;
}
If this doesn't help, please explain in more detail what is broken.
The problem here is the const in your declaration:
Group& Server::findGroup(unsigned int userId) const //<==THIS
That means that this is a const Server*, and thus everything in it is const as well, including groups. Which means that groups.begin() will return a const_iterator instead of an iterator.
One thing you can do (might not be a good idea; you need to be really sure!) would be to mark groups as mutable, which lets it be changed even if its enclosing object is const:
mutable vector<T> groups;
Doing this will make groups.begin() return a regular iterator.
But I would instead ask you to reevaluate why this method is declared const at all, since you're returning part of the object in a form that can be changed and thus you're not really honoring const.
I have a class (foo) that contains a vector.
If i try iterating over the elements in the vector like so:
for(vector<random>::iterator it = foo.getVector().begin();
it != foo.getVector().end(); ++it) {
cout << (*it) << endl;
}
The first element is always corrupted and returns garbage data.
However, if do something like:
vector<random> v = foo.getVector();
for(vector<random>::iterator it = v.begin();
it != v.end(); ++it) {
cout << (*it) << endl;
}
Everything appears to be working fine. Is there a "gotcha" that I do not know about?
I've also tried doing cout << foo.getVector()[0] << endl; outside of the loop but that appears to be working ok.
Thanks.
Edit:
Here's my header file:
#ifndef HITS
#define HITS
#include <vector>
#include "wrappers.h"
class Hits {
public:
Hits();
std::vector<word_idx_value> getVector() {return speech_hits;}
const std::vector<word_idx_value> getVector() const {return speech_hits;}
void add(const word_idx_value&);
Hits &operator+=(const Hits&);
private:
std::vector<word_idx_value> speech_hits;
};
#endif
for(vector<random>::iterator it = foo.getVector().begin();
The temporary vector is returned when you do foo.getVector() and it gets destroyed the moment ; is encountered after foo.getVector().begin(); Hence iterator becomes invalid inside the loop.
If you store the value of foo.getVector(); in vector v ( v = foo.getVector();) and then use the vector v, it works fine. It is because the vector v is valid throughout the loop.
getVector() returns a vector by value. The two invocations of getVector (begin() and end()) return different copies of the vector, so you call begin() on one object and end() on another. What you get is two iterators into two different containers. Comparing those two iterators with != yields an undefined value.
getVector() returns vector by value and in the first case you get a temporary variable that gets destroyed once you're inside the loop. In the second case you copy the result into a local variable that is still alive while inside the loop. Possible solution is to return vector by const reference.
You error is in the getVector() method.
Return by reference.
class Hits
{
public:
std::vector<word_idx_value>& getVector() {return speech_hits;}
// ^
// Add the & to return by reference.
// You may also want a const version at some point.
std::vector<word_idx_value> const& getVector() const {return speech_hits;}
If you don;t return by reference you are creating a temporary copy. The copy is then destroyed after it has been used. In this case after the begin() has executed the temporary object is destroyed, and thus the iterator returned by begin() is not valid.
modify the getVector function to return the object reference like this:
std::vector<word_idx_value>& getVector() {return speech_hits;}