For testing purposes, I'm running the following code through a for loop. Only the first three keys actually exist, and "Record found" is displayed as expected, along with the key, retrieved from findVertex->first.
My question is, how would I be able to access the second value being pointed to?
findVertex->secondseems obvious, but does not work, as the second value is an object I created, the declaration of which is given below the code, if it would be of any use.
for(int i = 0; i<10; i++)
{
map<int, vector<Vertex> >::const_iterator findVertex = vertexMap.find(i);
if(findVertex != vertexMap.end())
{
cout<<"\nRecord found: ";
cout<<findVertex->first;
cout<<findVertex->second; //does not work
}
else
cout<<"\nRecord not found";
}
Class code:
class Vertex
{
private:
int currentIndex;
double xPoint, yPoint, zPoint;
vector<double> attributes;
public:
friend istream& operator>>(istream&, Vertex &);
friend ostream& operator<<(ostream&, Vertex &);
};
Thanks
Your map is of the type
map<int, vector<Vertex>>
This means first is an int, and second is vector<Vertex>.
While you have defined operator<< for Vertex, there is no such function for vector<Vertex>. You'd have iterate through your vector, if you have access to C++11 you can use something like
if(findVertex != vertexMap.end())
{
cout << "\nRecord found: ";
cout << findVertex->first << '\n';
for (auto const& vertex : findVertex->second)
{
cout << vertex << '\n';
}
}
If you don't have access to C++11 you can do the same idea manually
if(findVertex != vertexMap.end())
{
cout << "\nRecord found: ";
cout << findVertex->first << '\n';
for (vector<Vertex>::const_iterator itVertex = findVertex->second.cbegin();
itVertex != findVertex->second.cend();
++itVertex)
{
Vertex const& vertex = *itVertex;
cout << vertex << '\n';
}
}
First of all you may not use const_iterator
map<int, vector<Vertex> >::const_iterator findVertex = vertexMap.find(i);
to display Vertex because you declared operator << with second parameter as a non-const reference
friend ostream& operator<<(ostream&, Vertex &);
^^^^^^^^
You should declare it like
friend ostream& operator<<(ostream&, const Vertex &);
^^^^^
Otherwise change the above statement to the following
map<int, vector<Vertex> >::iterator findVertex = vertexMap.find(i);
^^^^^^^^
And change this statement
cout<<findVertex->second; //does not work
to the following code snippet
for ( Vertex &v : findVertex->second ) cout << v << endl;
If you will modify the operator specyfying qualifier const for the second parameter then you can write
map<int, vector<Vertex> >::const_iterator findVertex = vertexMap.find(i);
^^^^^^^^^^^^^^
//...
for ( const Vertex &v : findVertex->second ) cout << v << endl;
^^^^^
Or instead of the range based for statement you can use an ordinary loop as for example
for ( std::vector<Vertex>::size_type i = 0; i < findVertex->second.size(); i++ )
{
std::cout << findVertex->second[i] << std::endl;
}
or
for ( std::vector<Vertex>::iterator it = findVertex->second.begin();
it != findVertex->second.end();
++it )
{
std::cout << *it << std::endl;
}
Related
I'm trying to overload the << operator to print a vector that contains elements of type Position (vector).
I managed to overload the << operator for type Position, but I can't figure out how to do it for vector. Can you help?
//position.h
#ifndef POSITION_H
#define POSITION_H
#include <iostream> // using IO functions
using namespace std;
class Position {
private:
int row;
int column;
public:
friend ostream& operator<<(ostream& os, const Position& P);
friend ostream& operator<<(ostream& os, const vector<Position>& VP);
};
#endif
//position.cpp
#include"Position.h"
#include <iostream> // using IO functions
#include<vector>
ostream& operator<<(ostream& os, const Position& P)
{
os << '(' << P.row << ',' << P.column << ')' << endl;
return os;
}
ostream& operator<<(ostream& os, const vector<Position>& VP)
{
Position placeholder;
for (int i = 0; i != VP.size(); i++)
{
placeholder = VP.at(i);
cout << placeholder << endl;
}
return os;
}
int main()
{
Position C1(2, 1);
Position C2(3, 1);
Position C3(4, 1);
vector<Position> cans;
cans.push_back(C1);
cans.push_back(C2);
cans.push_back(C3);
cout << cans;
system("pause");
}
I'm sure there's a duplicate on StackOverflow somewhere, but I cannot find it. I'm a bit surprised about this question, as I don't really see a critical issue at first sight. Did you get a compiler error or segmentation fault?
Every time you assign to Placeholder, you make a copy. This is not necessary at all: you can directly access the element at the index. As you limit the index to 0 to size(), you don't have to worry about going out-of-bounds, so don't use .at(i), which throws an exception if you go out of bounds. Just use VP[i].
Also not that std::endl flushes the buffer, which is slow. A normal enter/end-line can be achieved with the '\n' character.
Finally, using namespace std; is considered bad practice.
You have multiple options for processing the elements of the vector:
index-based for loop:
for (int i = 0; i != VP.size(); ++i) {
os << VP[i] << '\n';
}
Iterator-based for loop
for (auto it = cbegin(VP); it != cend(VP); ++it) {
os << *it << '\n';
}
range-based for loop
for (auto const& el : VP) {
os << el << '\n';
}
Algorithm for(each) loop
std::for_each(cbegin(VP), cend(VP),
[](auto const& el) { os << el << '\n'; });
Copy to ostream_iterator
std::copy(cbegin(VP), cend(VP),
std::ostream_iterator<Position>(os, "\n"));
Note that here you could also write <decltype(VP)::value> instead of <Position> to keep it generic, but that might be overkill in this situation.
And the last two have a C++20 ranges equivalent:
std::ranges::for_each(VP,
[](auto const& el) { os << el << '\n'; });
std::ranges::copy(VP,
std::ostream_iterator<Position>(os, "\n"));
Note:
friend ostream& operator<<(ostream& os, const vector<Position>& VP); doesn't have to be a friend of Position! It doesn't require access to the private members.
Hi there i was wondering if i could get some help with a problem i am having printing out the contents of a vector in C++
I am attempting to output all the variables of a class within one or two function calls in a particular order. However i am receiving an odd error when iterating through a vector
The error i am receiving is Error
error C2679: binary '=' : no operator found which takes a right-hand operand of type
'std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<std::basic_string<char,std::char_traits<char>,std::allocator<char>>>>>' (or there is no acceptable conversion)
My relevant code is below
ifndef idea
#define idea
using namespace std;
class Idea{
private:
int id;
string proposer, content;
vector<string> keywords;
public:
Idea(int i);
Idea(int i, string pro, string con);
void inputIdea();
int getID(){ return id; };
string getProposer(){ return proposer; };
string getContent(){ return content; };
vector<string> getKeyword();
bool wordSearch(string word);
friend ostream& operator<< (ostream& stream, const Idea& i);
void printIdea(ostream& os)const;
};
bool Idea::wordSearch(string word){
vector<string>::iterator it;
for(it = keywords.begin(); it < keywords.end(); it++){
if (word == *it){
return true;
}
}
if (content.find(word) != string::npos){
return true;
}
return false;
}
void Idea::printIdea(ostream& os)const{
vector<string>::iterator it;
os << "ID: " << id << endl;
os << "Proposer: " << proposer << endl;
os << "keywords: ";
for (it = keywords.begin(); it < keywords.end(); it++){ // error C2679
os << *it << " ,";
}
os << endl << "content: " << content << endl;
}
ostream& operator<<(ostream& os, const Idea& i)
{
i.printIdea(os);
return os;
}
i find it odd because the iterator function works in a different section of the code.
bool Idea::wordSearch(string word){
vector<string>::iterator it;
for(it = keywords.begin(); it < keywords.end(); it++){
if (word == *it){
return true;
}
}
if (content.find(word) != string::npos){
return true;
}
return false;
}
I wish to print out the id, then the proposer, then the keywords, then the content.
This is because printIdea is a const method. const methods aren't allowed to modify their members and thus keywords.begin() returns a vector<string>::const_iterator, not a normal one (vector<string>::iterator) . You should change the type of it :
vector<string>::iterator it;
to:
vector<string>::const_iterator it;
To have compatible types.
Or, if you have a compiler that has C++11 support you could just let the compiler figure it out for you:
auto it = keywords.begin()
printIdea is defined as
void Idea::printIdea(ostream& os)const
which means all non static members in that function are const qualified. Because of that keywords.begin() returns std::vector::const_iterator and not a std::vector::iterator. A std::vector::const_iterator is not assignable to a ``std::vector::iteratorwhich is howit` is declared so you get the error. You need to change
vector<string>::iterator it;
to
vector<string>::const_iterator it;
In order to get it to work.
Alternatively you can use a range based for loop and not even have to remember all of this like
for (auto& e : keywords)
{
os << e << " ,";
}
You need to use a const_iterator since your method printIdea() is const.
And you should use != to compare the iterator against end().
I am attempting to implement a std::list to replace a linked list in this assignment. I am not allowed to change the declarations and can only change code in the .cpp file. For the most part I am making progress but I am having trouble implementing this
std::ostream& operator<< (std::ostream& out, const Section& section);
namely when I try to create an iterator it fails. I've used the iterator elsewhere in the code so I don't understand why it's failing here, I believe it's because it's private but I'm not sure how to resolve the issue without changing the .h file which was explicitly prohibited:
std::ostream& operator<< (std::ostream& out, const Section& section)
{
// 1. print the section header
out << setw(8) << left << section.getCourse()
<< setw(6) << left << section.getCallNumber();
out << ": " << section.getNumberOfStudents() << " students\n";
// 2. collect the students, sort, and print
Student* students = new Student[section.getNumberOfStudents()];
{
int i = 0;
for ( auto pos = section.students.begin();
pos != section.students.end(); pos++)
{
students[i] = pos;
++i;
}
}
sort (students, students+section.getNumberOfStudents());
for (int i = 0; i < section.getNumberOfStudents(); ++i)
out << " " << students[i] << "\n";
out << flush;
return out;
}
students[i] = pos;
should be changed to
students[i] = *pos;
because you want to copy the Student the iterator references, not the iterator itself.
But why a dynamic array of Student rather than a std::vector<Student>? Currently you have a memory leak because you don't delete[] students;
Edit 1
Removed.
Edit 2
Other than that, all I can see that it wrong is a missing std:: in front of
sort (students, students+section.getNumberOfStudents());
this is assuming there is no custom sort method being used.
Edit 3
Going off the rails here:
students[i] = *pos;
copies a Student from the list into the dynamic array students. This could be expensive, so here is an alternative:
First the bits and pieces needed to prove this out: Required includes
#include <iostream>
#include <list>
#include <vector>
#include <algorithm>
#include <functional>
a minimal Student class
class Student
{
std::string name;
public:
Student(std::string inname):name(inname)
{
}
const std::string & getname() const
{
return name;
}
friend bool operator<(const Student & a, const Student &b)
{
return a.name < b.name;
}
};
a minimal Section class
class Section
{
public:
std::list<Student> students;
};
a minimal outstream operator
std::ostream& operator<<(std::ostream& out, const Section& section)
{
A std::vector instead of an array, and a vector of constant references so we don't have to copy the students.
std::vector<std::reference_wrapper<const Student>> students;
Store references in the vector. Probably could do a one liner with std::copy and std::back_inserter, but this is getting a bit too much to absorb for one example.
for (const auto & student: section.students)
{
students.push_back(std::ref(student));
}
Sort the vector
std::sort(students.begin(), students.end());
print the vector
for (const auto & student: students)
{
out << student.get().getname() << " ";
}
return out;
}
and one main to rule them all and in the darkness bind them
int main()
{
Section s;
s.students.emplace_front("Tom");
s.students.emplace_front("Dick");
s.students.emplace_front("Harry");
std::cout << s;
}
And all in one easy to cut-n-paste block:
#include <iostream>
#include <list>
#include <vector>
#include <algorithm>
#include <functional>
class Student
{
public:
std::string name; // this is me being lazy. name should be private
Student(std::string inname):name(inname)
{
}
const std::string & getname() const
{
return name;
}
friend bool operator<(const Student & a, const Student &b)
{
return a.name < b.name;
}
};
class Section
{
public:
std::list<Student> students;
};
std::ostream& operator<<(std::ostream& out, const Section& section)
{
std::vector<std::reference_wrapper<const Student>> students;
// store references in the `vector`.
for (const auto & student: section.students)
{
students.push_back(std::ref(student));
}
// Sort the `vector`
std::sort(students.begin(), students.end());
// print the `vector`
for (const auto & student: students)
{
out << student.get().getname() << " ";
}
return out;
}
int main()
{
Section s;
s.students.emplace_front("Tom");
s.students.emplace_front("Dick");
s.students.emplace_front("Harry");
std::cout << s;
}
Or do what Remy suggested and use a std::vector<Student *> and a custom comparator to dereference the pointers for std::sort.
As others have stated, the error is because you are not dereferencing the iterator when populating your students[] array:
students[i] = pos; // <-- should be *pos instead!
I would suggest an alternative approach that should be faster and more efficient:
std::ostream& operator<< (std::ostream& out, const Section& section)
{
// 1. print the section header
out << setw(8) << left << section.getCourse()
<< setw(6) << left << section.getCallNumber();
out << ": " << section.getNumberOfStudents() << " students\n";
// 2. collect the students, sort, and print
std::vector<const Student*> students;
students.reserve(section.getNumberOfStudents());
for ( auto pos = section.students.cbegin();
pos != section.students.cend(); ++pos)
{
students.push_back(&(*pos));
}
sort (students.begin(), students.end(),
[](const Student *a, const Student *b) { return (*a < *b); }
);
for ( auto pos = students.cbegin();
pos != students.cend(); ++pos)
{
out << " " << *(*pos) << "\n";
}
out << flush;
return out;
}
I appreciate all your answers. Ended up being a much more basic issue. I had to implement the Section iterators to return student iterators.
Section::iterator Section::begin() {
return students.begin();
}
Section::const_iterator Section::begin() const {
return students.begin();
}
Section::iterator Section::end() {
return students.begin();
}
Section::const_iterator Section::end() const {
return students.begin();
}
Hey I have a structure
typedef struct CLUSTERINFO{
unsigned cluster;
vector <string> scopids;
}clusterinfo;
It looks like i have some issues to assign the value in to the vector scopids and then print them out
multimap<unsigned, clusterinfo> classinfomap;
clusterinfo clinfo;
string id_req;
//vector<unsigned> cluster_req_list and clustersipinfomap are some known from previous modules
for (ib=cluster_req_list.begin(); ib !=cluster_req_list.end(); ib++)
{
if(clustersipinfomap.count(*ib)>0)
{
cout<<count1<<"\t"<<*ib<<"\t";
clinfo.cluster= *ib;
std::pair<multimap<unsigned,sipinfo>::iterator, multimap<unsigned,sipinfo>::iterator> ret;
set<string>id_req_list;
id_req_list.clear();
ret=clustersipinfomap.equal_range(*ib);
//obtain the id_req_list
for (multimap<unsigned, sipinfo>:: iterator ic=ret.first; ic!=ret.second; ++ic)
{
string id_tmp=ic->second.id;
id_req_list.insert(id_tmp);
*****(clinfo.scopids).push_back(id_tmp); //i got sth wrong here
}
again sth is wrong for printing out the vector in the structure;
multimap<unsigned, clusterinfo>::iterator ip;
for(ip= classinfomap.begin(); ip!=classinfomap.end(); ip ++)
{
cout<<ip->first <<"\t"<< ip->second.cluster<<endl;
for (unsigned it=0; it< (ip->second.scopids).size(); it++)
{
count<< (ip->second.scopids)[it] << endl;
}
}
How to "assign" a value to a vector in a structure: you probably want to add an element to the vector, which you can achieve with std::vector::push_back:
struct Foo
{
std::vector<std::string> vec;
};
Foo f;
std::string s("Hello, World!";
f.vec.push_back(s);
How to print out contents of the vector?
C++11
for (const auto& e : f.vec)
std::cout << e << " ";
std::cout << std::endl;
C++03
for (std::vector<std::string>::const_iterator it = f.vec.begin(); it != f.vec.end(); ++it)
std::cout << *it << " ";
std::cout << std::endl;
I am trying to understand a code, here is fragment which is causing confusion:
typedef map<int, Person, less<int> > people_map;
people_map people;
.
.
.
cout << "Erasing people of age 100" << endl;
for (people_map::iterator j = people.begin(); j != people.end();) {
if (j->second.GetAge() == 100)
{
people.erase(j++); // iterator is advanced before the erase occurs
}
else
++j; // advance the iterator
} // end of erase loop
the confusion is: if i want to increment j after the function call it causes segmentation fault. I am not able to understand why:
I change it to something like this:
if (j->second.GetAge() == 100)
{
temp = j++;
j--;
people.erase(j); // iterator is advanced before the erase occurs
j=temp;
}
causes segmentation fault.
or like this:
if (j->second.GetAge() == 100)
{
people.erase(j); // iterator is advanced before the erase occurs
j++;
}
causes segmentation fault.
here is the complete program listing:
// disable warnings about long names
#ifdef WIN32
#pragma warning( disable : 4786)
#endif
#include <string>
#include <map>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <iterator>
#include <functional>
using namespace std;
class Person {
// private members
string m_sName;
string m_sEmail;
int m_iAge;
public:
// constructor
Person(const string sName,
const string sEmail,
const int iAge) :
m_sName(sName), m_sEmail(sEmail), m_iAge(iAge) {
};
// default constructor
Person() : m_iAge(0) {
};
// copy constructor
Person(const Person & p) :
m_sName(p.m_sName), m_sEmail(p.m_sEmail), m_iAge(p.m_iAge) {
};
// operator =
Person & operator=(const Person & rhs) {
// don't assign to self
if (this == &rhs)
return *this;
m_sName = rhs.m_sName;
m_sEmail = rhs.m_sEmail;
m_iAge = rhs.m_iAge;
return *this;
};
// access private members
string GetName() const {
return m_sName;
};
string GetEmail() const {
return m_sEmail;
};
int GetAge() const {
return m_iAge;
};
}; // end of class Person
// function object to print one person
class fPrint {
ostream & m_os;
public:
// constructor - remember which stream to use
fPrint(ostream & os) : m_os(os) {
};
// person object arrives as a pair of key,object
void operator() (const pair <const int, const Person> & item) const {
m_os << "# " << item.first << " - name: "
<< item.second.GetName()
<< " - " << item.second.GetEmail()
<< ", age " << item.second.GetAge()
<< endl;
};
}; // end of class fPrint
// declare type for storing people (numeric key, person object)
typedef map<int, Person, less<int> > people_map;
int main(void) {
// make a map of people
people_map people;
// add items to list
people [1234] = Person("Nick", "nick#some-email-address.com", 15);
people [4422] = Person("Fred", "fred#nurk.com.au", 100);
people [88] = Person("John", "john#smith.com.au", 35);
// insert a different way ...
people.insert(make_pair(42, Person("Abigail", "abigail#blah.com.au", 22)));
// best to declare this on its own line :)
fPrint fo(cout); // instance of function output object
// print everyone (calls a function object to print)
cout << "Printing all using fPrint ..." << endl;
for_each(people.begin(), people.end(), fo);
// find someone by key
cout << "Finding person 4422 ..." << endl;
people_map::const_iterator i = people.find(4422);
if (i == people.end())
cout << "Not found." << endl;
else {
fo(*i); // dereference and print
// another way of printing -
// key itself is the "first" part of the map pair ...
cout << "Found key = " << i->first << endl;
// person object is the "second" part of the map pair...
cout << "Found name = " << i->second.GetName() << endl;
}
// Note, this will not work:
// fPrint (cout) (*i);
// However this will:
// 0, fPrint (cout) (*i);
// However I think the extra zero is a bit obscure. :)
// An alternative way of finding someone.
// Note - this will add them if they are not there.
// Since this is a reference changing it will change the person in the
// map. Leave off the & to get a copy of the person.
Person & p = people [1234];
cout << "Person 1234 has name " << p.GetName() << endl;
// Example of erasing an element correctly ...
// If we did the j++ as part of the for loop we would end up
// adding 1 to an iterator that pointed to an element that was
// removed which would lead to a crash. See Josuttis p 205.
cout << "Erasing people of age 100" << endl;
for (people_map::iterator j = people.begin(); j != people.end();) {
if (j->second.GetAge() == 100)
{
people.erase(j++); // iterator is advanced before the erase occurs
}
else
++j; // advance the iterator
} // end of erase loop
// now display who is left
cout << "Printing people left after erase ..." << endl;
for_each(people.begin(), people.end(), fo);
return 0;
} // end of main
erase invalidates the iterator to the erased element.
if (j->second.GetAge() == 100)
{
temp = j++;
j--;
people.erase(j); // iterator is advanced before the erase occurs
j=temp;
}
This doesn't work because you set temp equal to the old value of j, and hence you'll keep using the invalidated iterator. The result of post-increment is the original value of the operand.
I suppose you could also do it like this, which is functionally the same as the working code, except it doesn't use the temporary result of post-increment:
if (j->second.GetAge() == 100) {
temp = j;
++j;
people.erase(temp);
}
Erase invalidates your iterator, this is why postfix increment is used. It doesn't pass advanced iterator to erase, it passes current iterator but advances as a sideffect.
people_map::iterator erase_it = j++;
people.erase(erase_it);
You have a problem with postfix increment, this is why your attempts have failed.
int i = 1;
int j = i++; // j == 1, i == 2