'incrementing a counter for every object [closed]
I have a class called Student, and in that class I have a std::map of books that looks like this:
std::map<std::string,int>books;
The string is the book name, and the int is the number of students that have the same book.
Then I create a new Student, and when I do I want that Student to also get the same books, so I do a copy like this:
new_student->getBookmap() = old_student->getBookmap();
new_student_3->getBookmap() = old_student->getBookmap();
getBookmap() returns the map for each Student. I have them as private members.
The new Student gets the exact copy of the same map, and now I want to increase the counter, but the counter should also be increased for all three Students.
But, if I increase the counter for one Student, the other Students' counters don't increase.
for (auto it = new_student->getBookmap().begin(); it != new_student->getBookmap().end(); it++)
{
it->second++;
}
When I do this, the counter only increases for the new_student, and not for old_student and new_student_1.
Could someone help me out?
Solution 1:[1]
The problem with your code is that each Student object has its own copy of the std::map. You need them to share a single std::map object instead.
The simplest way to share the books field is to make it a static member of Student, then you don't need to copy it around at all, eg:
using bookCounter = std::map<std::string, int>;
class Student {
private:
static bookCounter books;
...
void checkoutBook(std::string bookName);
void returnBook(std::string bookName);
...
};
bookCounter Student::books;
void Student::checkoutBook(std::string bookName)
{
books[bookName]++;
}
void Student::returnBook(std::string bookName)
{
books[bookName]--;
}
int main()
{
...
new_student = new Student();
new_student->checkoutBook("...");
...
new_student->returnBook("...");
...
}
Or, you can declare books as a global variable, say near main(), and then just refer to that variable inside of Students when needed, eg:
class Student {
...
};
using bookCounter = std::map<std::string, int>;
extern bookCounter books;
void Student::checkoutBook(std::string bookName)
{
books[bookName]++;
}
void Student::returnBook(std::string bookName)
{
books[bookName]--;
}
bookCounter books;
int main()
{
...
}
Or, you could make books be a local variable of main() itself, and then you can pass a pointer/reference to it to each Student, eg:
using bookCounter = std::map<std::string, int>;
class Student {
private:
bookCounter &books;
...
public:
Student(bookCounter &books) : books(books) {}
...
void checkoutBook(std::string bookName);
void returnBook(std::string bookName);
...
};
void Student::checkoutBook(std::string bookName)
{
books[bookName]++;
}
void Student::returnBook(std::string bookName)
{
books[bookName]--;
}
int main()
{
bookCounter books;
...
new_student = new Student(books);
new_student->checkoutBook("...");
...
new_student->returnBook("...");
...
}
Alternatively, you might consider using std::shared_ptr to share a single std::map object amongst the various Student objects, eg:
using bookCounter = std::map<std::string, int>;
class Student {
private:
std::shared_ptr<bookCounter> books;
...
public:
Student(std::shared_ptr<bookCounter> books) : books(books) {}
...
void checkoutBook(std::string bookName);
void returnBook(std::string bookName);
...
};
void Student::checkoutBook(std::string bookName)
{
(*books)[bookName]++;
}
void Student::returnBook(std::string bookName)
{
(*books)[bookName]--;
}
int main()
{
auto books = std::make_shared<bookCounter>();
...
new_student = new Student(books);
new_student->checkoutBook("...");
...
new_student->returnBook("...");
...
}
In which case, you might instead consider changing the std::map into a std::vector of std::shared_ptr<Book> objects, to share individual book objects rather then just strings, and not manage your own counters at all (std::shared_ptr has its own counter, which you can query via its use_count() method), eg:
struct Book : std::enable_shared_from_this<Book>
{
std::string name;
...
int checkoutCount() const;
[[nodiscard]] static std::shared_ptr<Book> create();
private:
Book() = default;
};
using bookPtr = std::shared_ptr<Book>;
class Student {
private:
std::vector<bookPtr> books;
...
public:
...
void checkoutBook(std::string bookName);
void returnBook(std::string bookName);
...
};
std::vector<bookPtr> library;
std::shared_ptr<Book> Book::create()
{
return std::shared_ptr<Book>(new Book);
}
int Book::checkoutCount() const
{
auto pthis = shared_from_this();
return (pthis.use_count() - 2); // not counting pthis and the library ...
}
void Student::checkoutBook(std::string bookName)
{
auto iter = std::find_if(library.begin(), library.end(),
[&](bookPtr &book){ return book->name == bookName; }
);
if (iter != library.end())
books.push_back(*iter);
}
void Student::returnBook(std::string bookName)
{
auto iter = std::find_if(books.begin(), books.end(),
[&](bookPtr &book){ return book->name == bookName; }
);
if (iter != books.end())
books.erase(*iter);
}
int main()
{
// populate library with Books as needed...
...
new_student = new Student();
new_student->checkoutBook("...");
...
new_student->returnBook("...");
...
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
