Trouble with C++ maps and their content - c++

This is rather extensive, so in advance, if you get through this, even without an answer or solution, thank you.
So, I have this program that is meant to be a basic social network, minus the user-interface, in which a user is represented by a Person object, which is responsible for maintaining a friend list, a block list, a list of messages, and a queue of pending friend requests. These lists are, respectively, of types std::map<std::string, Person>, std::map<std::string, Person>, std::vector<Message>, and std::queue<Message>, where the std::string for the two maps is a concatenation of the user's first and last names and the Message in the final two containers are and additional class I have defined. I have overloaded the << operator for Person such that it prints the user's first and last names, with a space in between. For some reason, when I go to print these names out, the return is empty, and I have no idea why. The following code is essentially a walkthrough what is happening.
The lines I am using to test my code in the main class:
std::string cFirst ("Chris");
std::string cLast ("Cringle");
SocialNetwork sn;
sn.addUser(cFirst,cLast);
The addUser() function in SocialNetwork:
void SocialNetwork::addUser(std::string first, std::string last){
std::string name = (first + last);
Person user (first, last);
_users.insert(std::pair<std::string, Person>(name, user));
}
Where _users is member data on the SocialNetwork of type std::map<std::string, Person>. The constructor for Person is:
Person::Person(std::string first, std::string last){
_first = first;
_last = last;
}
Where _first and _last are member data on Person that represent the user's first and last names. Then, back in the main class, after sn.addUser(cFirst,cLast);:
sn.printUsers();
Which looks like:
void SocialNetwork::printUsers(){
std::map<std::string, Person>::iterator it;
it = _users.begin();
while(it != _users.end()){
cout << it->first << endl;
cout << it->second << endl;
it++;
}
}
With the given code I have, the expected output for cout << it->first << endl; should be ChrisCringle, and it is. The expected output for cout << it->second << endl; should call the overloaded operator and should be Chris Cringle, but it simply prints a blank space. Any indications as to why would be greatly appreciated. Do I need to pass my params by reference? I have tried this already and seem to run into a lot of trouble. If something appears to be missing that may help, feel free to ask! Thanks again! I know I'll probably get a lot of flak for this long question but I do not think I can manage to make this any more of a simple question.
EDIT: The code for the overloaded operator is:
ostream& operator<<(ostream& os, const Person& per){
os << per._first << " " << per._last;
return os;
}

I just used all the code you've shown: http://ideone.com/mFBxTC
#include <string>
#include <iostream>
#include <map>
using namespace std;
struct Person {
Person(std::string first, std::string last);
std::string _first, _last;
};
ostream& operator<<(ostream& os, const Person& per){
os << per._first << " " << per._last;
return os;
}
struct SocialNetwork {
void addUser(std::string first, std::string last);
std::map<std::string, Person> _users;
void printUsers();
};
void SocialNetwork::addUser(std::string first, std::string last){
std::string name = (first + last);
Person user (first, last);
_users.insert(std::pair<std::string, Person>(name, user));
}
Person::Person(std::string first, std::string last){
_first = first;
_last = last;
}
void SocialNetwork::printUsers(){
std::map<std::string, Person>::iterator it;
it = _users.begin();
while(it != _users.end()){
cout << it->first << endl;
cout << it->second << endl;
it++;
}
}
int main() {
std::string cFirst ("Chris");
std::string cLast ("Cringle");
SocialNetwork sn;
sn.addUser(cFirst,cLast);
sn.printUsers();
return 0;
}
And it works fine. So error is elsewhere
Thats why one should post SSCCE when posting debugging questions.

Related

priority queue using class object

I am trying to make a priority queue with Student class.
I overloaded operator< function which compare student id of two objects of Student class, but my code does not work.
Could you give me any advice?
#include <iostream>
#include <queue>
#include <vector>
#include <string>
using namespace std;
class Student {
public:
string name;
int id;
Student(string str, int n) {
this->name = str;
this->id = n;
};
};
bool operator<(const Student& a, const Student& b) {
return a.id < b.id;
}
int main() {
priority_queue<Student> pq;
pq.push(Student("Miria", 1));
pq.push(Student("Ken", 2));
pq.push(Student("Bob", 3));
while (!pq.empty()) {
cout << pq.top() << endl;
pq.pop();
}
return 0;
}
I am kind of unaware what an "My code does not work seems", although it seems to me that you are not printing the objects in the priority_queue correctly.
The appropriate way of printing them will be by using the object's properties or using a string representation operator overload. Let me give you an example of how the simpler version of the code would look like by using your code:
cout << pq.top().name << "'s id is: " << pq.top().id << endl;
The reason your code is not working is because you are lacking the output operator overload. You are not able to compile the program itself if you are lacking this operator.
The former spoken of is done the foreshown code down below:
friend ostream& operator<<(std::ostream& output, const Student& obj) {
return output << obj.name << "'s id is: " << obj.id << endl;
};
This way you will be able to use the pq.top() function in the cout stream:
cout << pq.top();
I hope this is what you expect and if you want to make it in increase order like Java you can use priority_queue.
The expected output as the question is described should be:
Bob's id is: 3
Ken's id is: 2
Miria's id is: 1

C++ Output via copy()

I'm playing with C++ and the STL and I've attempted to copy a deque into a list and print the list via copy() and ostream_iterator. For some reason, the contents of the list I copied to doesn't print unless I access the elements via front(), back(), or at(). Why do the first two printing attempts fail:
#include <iostream>
#include <fstream>
#include <deque>
#include <algorithm>
#include <iterator>
#include <list>
using namespace std;
void alterParticle(string&);
int main(){
string tmp_str;
deque<string> d;
list<string> l;
ifstream in("foo.txt");
if(!in.is_open()){
cout << "Error opening file" << endl;
return 1;
}
while(in){
getline(in,tmp_str);
d.push_back(tmp_str);
}
for_each(d.begin(),d.end(),alterParticle);
copy(d.begin(),d.end(),ostream_iterator<string>(cout,"\n"));
ostream_iterator<string> out(cout,"\n");
copy_if(d.begin(),d.end(),out,
[](const string& s){
if(s.find("fooparticle")!= string::npos)
return true;
return false;
});
copy_if(d.begin(),d.end(),l.begin(),
[](const string& s){
if(s.find("fooparticle")!= string::npos)
return true;
return false;
});
cout << "First try: " << endl;
for(string s : l)
cout << s << endl;
cout << "Second try: " << endl;
copy(l.begin(),l.end(),out);
cout << "Last try: " << l.front() << endl;
return 0;
}
void alterParticle(string& s){
int fpos = s.find("quark");
string rep_str{"quark"};
if(fpos != string::npos){
s.replace(s.find(rep_str),rep_str.length(),"fooparticle");
}
}
Output:
fooparticle 10 11.4
neutrino 7 20.5
electron 5 6.7
proton 8 9.5
fooparticle 10 11.4
First try:
Second try:
Last try: fooparticle 10 11.4
Edit:
Just so it's easier to see why this didn't work for anyone who asks the same question, here are the semantics of copy_if(). It makes it pretty clear that it does not expand the container:
template <class InputIterator, class OutputIterator, class UnaryPredicate>
OutputIterator copy_if (InputIterator first, InputIterator last,
OutputIterator result, UnaryPredicate pred)
{
while (first!=last) {
if (pred(*first)) {
*result = *first;
++result;
}
++first;
}
return result;
}
copy and copy_if do not add new elements to the list, they assume there are existing elements to copy into. Your list is initially empty and thus you are writing to the begin() == end() iterator of the list. This does not increase the list size (which is why the first two attempts print nothing), but if you access the (not actually existing) first list member, you might get the result that was written there.
Needless to say, assigning to the end() iterator is undefined behavior.
You can keep using copy and friends if you use an insert_iterator (you'd generally use back_inserter), similar to the ostream_iterator you are already using.

Unable to output vector with an ostream output C++

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().

using iterator in ostream fails

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();
}

C++ List Iterators accessing different elements in the same object

for List Iterators i can access different elements
but i can only access one thing per object
eg
class student{
private :
string firstname;
string lastname;
// some other variables //etc...
public:
// some functions here ....
};
in the list i can access and print all the first name with the List Iterators
but how do I print
first name follow by last name in a List ?
This is what I think you're talking about: if not, please give some more details.
I take it you've got a std::list of student, like
std::list<student> studentList;
//add student instances to list
And then you're iterating over it, something like so:
for(std::list<student>::it = studentList.begin(); it != studentList.end(); ++it)
{
std::cout << it->getFirstName() << std::endl;
}
If this is the case, just add a bit more for it->getLastName():
for(std::list<student>::it = studentList.begin(); it != studentList.end(); ++it)
{
std::cout << it->getFirstName() << " " << it->getSecondName() << std::endl;
}
You can print lastname in the same way, you print the firstname. If you print it in a member function of the class, then you can do this:
std::cout <<firstname <<" " <<lastname << std::endl;
And if you've written some get functions , and you print it from non-member function of the class, then you can do this:
student s;
//...
std::cout <<s.getFirstname() <<" " <<s.getLastname() << std::endl;
You can also add operator<< friend function to the class, as:
class student{
private :
string firstname;
string lastname;
// some other variables //etc...
public:
// some functions here ....
friend std::ostream& operator<<(std::ostream & out, const student &s)
{
return out << s.firstname <<" " <<s.lastname;
}
};
then do this:
std::list<student> students;
//...
for(std::list<student>::iterator it = students.begin(); it != students.end(); it++ )
{
std::cout << *it << std::endl;
}
And you can do even this:
student s;
//...
std::cout << s << std::endl; //it prints firstname and lastname by calling operator<<
Simple ! cout the firstname it followed by the last name.
cout << lIter->firstName << " " << lIter->lastName << endl ;
// firstName, lastName are private. So, intead write getters and call those on list iterator.
Or did I understand the question wrong ?