Why am I getting errors in the following function? [duplicate] - c++

I have a vector of Student which has a field name.
I want to iterate over the vector.
void print(const vector<Student>& students)
{
vector<Student>::iterator it;
for(it = students.begin(); it < students.end(); it++)
{
cout << it->name << endl;
}
}
This is apparently illegal in C++.
Please help.

You have two (three in C++11) options: const_iterators and indexes (+ "range-for" in C++11)
void func(const std::vector<type>& vec) {
std::vector<type>::const_iterator iter;
for (iter = vec.begin(); iter != vec.end(); ++iter)
// do something with *iter
/* or
for (size_t index = 0; index != vec.size(); ++index)
// do something with vec[index]
// as of C++11
for (const auto& item: vec)
// do something with item
*/
}
You should prefer using != instead of < with iterators - the latter does not work with all iterators, the former will. With the former you can even make the code more generic (so that you could even change the container type without touching the loop)
template<typename Container>
void func(const Container& container) {
typename Container::const_iterator iter;
for (iter = container.begin(); iter != container.end(); ++iter)
// work with *iter
}

Use const_iterator instead. An iterator allows modification of the vector, so you can't get one from a const container.
Also, the idiomatic way to write this loop uses it != students.end() instead of < (though this should work on a vector).

C++11 style:
void print(const vector<Student>& students) {
for(auto const& student : students) {
cout << student.name << endl;
}
}

Instead of vector<Student>::iterator, use vector<Student>::const_iterator.

void print(const vector<Student>& students)
{
vector<Student>::const_iterator it; // const_iterator
for(it = students.begin(); it != students.end(); it++)
{
cout << it->name << endl;
}
}

void print(const vector<Student>& students)
{
for(auto it = students.begin(); it != students.end(); ++it)
{
cout << it->name << endl;
}
}

Related

Nested range-based for-loops

I have the following code using range-based for-loops (C++11):
vector<atom> protein;
...
for(atom &atom1 : protein) {
...
for(atom &atom2 : protein) {
if(&atom1 != &atom2) {
...
}
}
}
Is there a better/cleaner/faster way to write this nested loops? Isn't there a way to include the if condition in the second loop?
Similar to ronag's answer is a more generic version:
template<typename C, typename Op>
void each_unique_pair(C& container, Op fun)
{
for(auto it = container.begin(); it != container.end() - 1; ++it)
{
for(auto it2 = std::next(it); it2 != container.end(); ++it2)
{
fun(*it, *it2);
fun(*it2, *it);
}
}
}
UPDATE
template<typename C, typename O1, typename O2>
void each_value_and_pair(C& container, O1 val_fun, O2 pair_fun)
{
auto it = std::begin(container);
auto end = std::end(container);
if(it == end)
return;
for(; it != std::prev(end); ++it)
{
val_fun(*it);
for(auto it2 = std::next(it); it2 != end; ++it2)
{
pair_fun(*it2, *it);
pair_fun(*it, *it2);
}
}
}
Which is used like this:
main()
{
std::vector<char> values;
// populate values
// ....
each_value_and_pair(values,
[](char c1) { std::cout << "value: " << c1 << std::endl;},
[](char c1, char c2){std::cout << "pair: " << c1 << "-" << c2 << std::endl;});
}
Sad but true.
How about normal loops with iterators and auto keyword?
I think this might be what you are looking for:
for(auto it1 = std::begin(protein1); it1 != std::end(protein); ++it1)
{
for(auto it2 = std::next(it1); it2 != std::end(protein); ++it2)
{
auto& atom1 = *it1;
auto& atom2 = *it2;
// ...
}
}
you're method is just fine.
if you want to save the if statement you can
vector<atom> protein;
int i, j;
...
for(i = 0; i < protein.size() : i++) {
atom &atom1 = protein.at(i);
for(j = i+1; j < protein.size() ; j++) {
atom &atom2 = protein.at(j);
// Do something
// Swap the atom2 and atom1
// Do something again
}
}

combine output from many containers in c++

I'm not very familiar with iterators in C++. Basically I have a container, which was written by someone else, which I do populate with records (I create many containers). However, I need to output tuples, instead each container separately as e.g.:
a1 | a2 | ... | an
given that each a's belong to separate containers. I will take as an e.g., a vector container:
vector<int> v;
vector<int>::iterator iter;
v.push_back(1);
v.push_back(2);
v.push_back(3);
for (iter = v.begin(); iter != v.end(); iter++)
cout << (*iter) << endl;
The code above will output records only from one containers, but I need to combine output from many containers (all the same length), how would I go on constructing tuples from all of them?
thanx in advance!
If your project is using Boost already, you could use zip_iterator.
You can also try to implement a simpler version of it (the full implementation is quite complicated).
You can use indices, if container supports random-access, for example
for (size_t i = 0; i < v.size(); ++i)
{
cout << v[i] << " " << v1[i] << endl;
}
You can use many iterators
vector<int>::iterator iter1;
for (iter = v.begin(), iter1 = v1.begin(); iter != v.end(); ++iter, ++iter1)
{
cout << *iter << " " << *iter1 << endl;
}
Further to pmr's answer and your comment thereon seeking a pointer towards implementation, the basic idea for a "zipping" iterator is easy to realise:
#include <iostream>
#include <vector>
template <typename T, typename U>
struct Zip
{
Zip(const T& t, const U& u, char sep = '|')
: it_(t.begin()), iu_(u.begin()), te_(t.end()), ue_(u.end()), sep_(sep)
{ }
Zip& operator*() const { return *this; }
Zip& operator++() { ++it_; ++iu_; return *this; }
operator bool() const { return it_ != te_ && iu_ != ue_; }
friend std::ostream& operator<<(std::ostream& os, const Zip& z)
{
return os << *z.it_ << z.sep_ << *z.iu_;
}
private:
typename T::const_iterator it_, te_;
typename U::const_iterator iu_, ue_;
char sep_;
};
int main()
{
std::vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
std::vector<std::string> v2;
v2.push_back("one");
v2.push_back("two");
v2.push_back("three");
v2.push_back("four");
for (Zip<std::vector<int>, std::vector<std::string> > zip(v1, v2); zip; ++zip)
std::cout << zip << '\n';
}
You could create a Zip iterator with one/both sides being a Zip iterator to handle more (than 2) iterators, or generalise the above using variadic templates.
vector<int> v;
set<float> v2;
vector<int>::iterator iter;
set<float>::iterator iter2;
for (iter = v.begin(), iter2 = v2.begin();
iter != v.end() && iter2 != v2.end();
++iter, ++iter2)
cout << (*iter) << (*iter2) << endl;
Keep in mind that this loop iterates at most as much as the length of the smallest container.

Generic Iterators to access vectors

I would like to know if I can have a generic iterator to access the elements in the the vectors. I have for different vectors but only one function to display the elements.
If I can have a generic iterator than my method can work out smoothly. Please advice if it is possible.
Point2,Point3,Line2,Line3 are 4 different classes. The method takes in a vector object which I have created in another method.
template <typename VecObject>
void Display(VecObject v) {
if (filterCriteria == "Point2") {
vector<Point2>::iterator it;
} else if (filterCriteria == "Point3") {
} else if (filterCriteria == "Line2") {
} else if (filterCriteria == "Line3") {
}
for ( it = v.begin(); it!=v.end(); ++it) {
cout << *it << endl;
}
}
This what i used to do ealier and it work find. I now need to to implement using iterators
//for (int i = 0; i < v.size(); i++) {
// cout << v[i];
// }
You have access to a vector's iterator types via iterator and const_iterator, so you need no switching:
template <typename VecObject>
void Display(const VecObject& v) {
typename VecObject::const_iterator it;
for ( it = v.begin(); it!=v.end(); ++it) {
cout << *it << endl;
}
}
Note that I changed the signature to take a const reference as opposed to a value. With the original signature, you would be needlessly copying the vector each time you call the function.
Alternatively, you can implement the function to take two iterators:
template <typename Iterator>
void Display(Iterator first, Iterator last) {
for (Iterator it = first; it!=last; ++it) {
cout << *it << endl;
}
}
and call it like this:
Display(v.begin(), v.end());
template<typename VectorObject>
void Display(VecObject v) {
typename VectorObject::const_iterator it = v.begin();
for (; it!=v.end(); ++it) {
cout << *it << endl;
}
}
Assume that your VectorObject implements iterators you can access to it's iterator type directly.
Usage:
int main()
{
std::vector<int> intv(2, 5);
std::vector<float> fv(2, 10);
Display(intv);
Display(fv);
return 0;
}

Why do I get a segmentation fault while iterating through this vector?

I need to go through this vector and delete the duplicates. A segmentation fault is occurring somewhere within this code. My guess is that it has something to do with deleting elements while the iterator is going through, but I don't really have a concrete understanding of how these iterators are actually working yet, so I can't figure it out.
vector<char *>::iterator iter;
for (iter = v->begin(); iter != v->end()-1; iter++ ){
char *aString = *iter;
int n = 1;
while(iter+n != v->end()){
int comparison = strcmp(aString, *(iter+n));
if(comparison == 0){
v->erase(iter + n);
}
n++;
}
}
Really, you just have a couple off-by-one problems here. You were comparing incorrectly against end() and incrementing n when you erased an element:
for (iter = v->begin(); iter != v->end()-1; iter++ ){
^^^^^^^^
And
while(iter+n != v->end())
^^
The following will do what you want (and demonstrate that it works):
int main()
{
std::vector<const char*> v (4, "this");
std::vector<const char *>::iterator iter;
for (iter = v.begin(); iter < v.end(); iter++ ) {
std::cout << *iter << " ";
}
std::cout << std::endl;
for (iter = v.begin(); iter < v.end(); iter++ ){
const char *aString = *iter;
int n = 1;
while(iter+n < v.end()){
int comparison = strcmp(aString, *(iter+n));
if(comparison == 0){
v.erase(iter + n);
}
else
n++;
}
}
for (iter = v.begin(); iter < v.end(); iter++ ) {
std::cout << *iter << std::endl;
}
}
Output is:
this this this this
this
You are not properly iterating through the remainder of the vector. An alternative to what Beta suggested is to use erase-remove with remove_if. Like this:
bool compare_strings(char * aString,char * bString)
{
return 0==strcmp(aString,bString);
}
void remove_duplicates(vector<char *> * v)
{
vector<char *>::iterator iter;
for (iter = v->begin(); iter != v->end(); iter++ ) {
v->erase(std::remove_if(iter+1,v->end(),compare_strings),v->end());
}
}
When you erase an element from the vector, the vector gets one element shorter. Try this:
if(comparison == 0){
v->erase(iter + n);
}
else{
n++;
}
Erasing from a vector invalidates all iterators from the erasee onwards, so you should probably not construct your loop the way you do, and rather use a standard idiom like this:
for (auto it = v.begin(); it != v.end(); ++it) // no end() - 1 -- may not be legal!
{
for (auto jt = it; jt != v.end(); )
{
if (jt == it) continue;
if (strcmp(*it, *jt) == 0)
{
jt = v.erase(jt);
}
else
{
++jt;
}
}
}
This code avoids the check for an empty vector, which your code fails to account for.

How do I iterate over a Constant Vector?

I have a vector of Student which has a field name.
I want to iterate over the vector.
void print(const vector<Student>& students)
{
vector<Student>::iterator it;
for(it = students.begin(); it < students.end(); it++)
{
cout << it->name << endl;
}
}
This is apparently illegal in C++.
Please help.
You have two (three in C++11) options: const_iterators and indexes (+ "range-for" in C++11)
void func(const std::vector<type>& vec) {
std::vector<type>::const_iterator iter;
for (iter = vec.begin(); iter != vec.end(); ++iter)
// do something with *iter
/* or
for (size_t index = 0; index != vec.size(); ++index)
// do something with vec[index]
// as of C++11
for (const auto& item: vec)
// do something with item
*/
}
You should prefer using != instead of < with iterators - the latter does not work with all iterators, the former will. With the former you can even make the code more generic (so that you could even change the container type without touching the loop)
template<typename Container>
void func(const Container& container) {
typename Container::const_iterator iter;
for (iter = container.begin(); iter != container.end(); ++iter)
// work with *iter
}
Use const_iterator instead. An iterator allows modification of the vector, so you can't get one from a const container.
Also, the idiomatic way to write this loop uses it != students.end() instead of < (though this should work on a vector).
C++11 style:
void print(const vector<Student>& students) {
for(auto const& student : students) {
cout << student.name << endl;
}
}
Instead of vector<Student>::iterator, use vector<Student>::const_iterator.
void print(const vector<Student>& students)
{
vector<Student>::const_iterator it; // const_iterator
for(it = students.begin(); it != students.end(); it++)
{
cout << it->name << endl;
}
}
void print(const vector<Student>& students)
{
for(auto it = students.begin(); it != students.end(); ++it)
{
cout << it->name << endl;
}
}