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;}
Related
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 am attempting to construct a binary search tree using a generalized list in C++.
class Element
{
private:
list<Element*> _children;
char* _name;
// and other data members/methods...
}
As you can see, I have a class "Element" and it has a list "_children" of Element pointers.
I am trying to access these children so that I may add children to them and so forth...
However, I cannot modify these values with my current method of using a "const_iterator" and my reason for doing that is that the "begin()" method of _children returns a const_iterator.
Someone help? Thank you :)
UPDATE: Thank you all so much... It turns out, I mistakenly had a method return a const reference of the _children data member.
const list<Element*>& getChildren();// return [_children]
I just deleted const and it works perfect now. Thank you! :D
The begin function will return a const_iterator if the list is const. So for the _children list you should be able to just get the standard iterator to let you perform non-const operations on it:
list<Element*>::iterator it = _children.begin();
This however won't work if your passing off a const reference to the list and then trying to get the non-const iterator from that. Something like this would not be allowed:
void doSomething( const list<Element*>& l )
{
list<Element*>::iterator it = l.begin();
}
You would need to instead pass a non-const reference to the list.
The other case where this would be not allowed is in a const function, i.e.
void doSomething() const
{
list<Element*>::iterator it = _children.begin();
}
But would need to see more of your code to confirm if you're doing this or not.
If you want to use _children as an array, how about trying std::vector class instead of std::list?
Here's usage.
#include <iostream>
#include <vector>
int main(void) {
std::vector<int> list;
list.push_back(1);
list.push_back(2);
list.push_back(3);
for (int i = 0; i < list.capacity();++i){
std::cout << list[i] << std::endl;
}
return 0;
}
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'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.
I'm learning C++ and can't get my head around this problem:
I have a simple class A
class A {
private:
int ival;
float fval;
public:
A(int i = 0, float f = 0.0) : ival(i), fval(f) { }
~A(){ }
void show() const {
cout << ival << " : " << fval << "\n";
}
void setVal(int i) {
ival = i;
}
//const getters for both ival and fval
//used for the default "lesser"
friend bool operator<(const A& val1, const A& val2) {
return val1.ival < val2.ival ? true : false;;
}
}
Then I have a regular set<A> myset that gets filled with insert(A(2, 2.2)); in a loop.
Iterating to get all the values is not a problem but I want to modify the value within this iteration:
for(set<A>::iterator iter = set3.begin(); iter != set3.end(); iter++) {
iter->setVal(1);
}
I assume that this should be doable, like you would do it in Java within a foreach loop. When compiling I get error: passing ‘const A’ as ‘this’ argument of ‘void A::setVal(int)’ discards qualifiers.
Looking at the sources of the STL set, i see that begin() is only available as a const method and I think this might be the problem. Messing around with const on the setVal() method got always the same error and wouldn't make much sense since I want to modify the value of A.
Is this the wrong approach of changing a bunch of A's values with a loop?
The STL set does not let you change values it stores. It does that by returning a copy of the object through the iterator (not the actual one in the set).
The reason that set does this is because it's using < to order the set and it doesn't want to remake the entire tree every time you dereference the iterator, which it would have to do, since it doesn't know if you changed anything that changes the ordering.
If you need to update the set<>, remove the old value and add in a new one.
EDIT: just checked source to SGI STL and it says this:
typedef typename _Rep_type::const_iterator iterator;
So, a set::iterator is just a set::const_iterator
From this page, it seems that begin() exists as well as a non-const method.
Perhaps your set is passed into the method as a const reference ?
EDIT
The referenced page is wrong. As Scharron states, there is no non-const begin() (or end() for that matter) method for ordered containers.
I will inform the website about their mistake (it's not the first they made ;))