First of all, this code:
set_list.insert(temp);
doesn't store a reference in your set even though you are using a reference to an object in your std::deque
. A copy of the object is made when you insert into the set because STL containers don't allow you to store references. However, you can store pointers in them, and with pointers you avoid the copies being made in the two containers.
The other issue you've got is that the iterator that std::set
returns, for both set<T>::const_iterator
and set<T>::iterator
, is a const iterator. There's a reason for this: it is an ordered container. Changing the elements can affect the ordering, rendering the std::set
invalid. Internally it's implemented as a red-black tree and it wouldn't know of changes you make to keys. That's why you shouldn't do it.
However, in your case it looks like the name
field of each book
element is not part of the key. So it's possible to update that without affecting the ordering.
To overcome both issues, you could change the set to be of type:
std::set<std::shared_ptr<book>, CompareBook>
where CompareBook
is a custom comparator. Using a shared pointer, you can refer to the same book
object in both your deque and set.
You could also make the comparator transparent, meaning that you could search for book by the something that is semantically a key, even if it is not technically a key. In your case the x
and y
values. To make things easier, you could define a struct for the key that encapsulates these two fields:
struct Point {
int x;
int y;
bool operator < (const Point& v) const {
if (y == v.y) {
return x < v.x;
}
else {
return y < v.y;
}
}
};
struct book
{
book(int x, int y, std::string name): point{x, y}, name{name} {}
Point point;
std::string name;
};
Putting all this together, you would have a comparator like this:
struct CompareBook
{
using is_transparent = void; //this typedef allows you to search by something other than the key
bool operator()(const std::shared_ptr<book>& book1, const std::shared_ptr<book>& book2) const
{
return book1->point < book2->point;
}
bool operator()(const Point &point, const std::shared_ptr<book>& book) const
{
return point < book->point;
}
bool operator()(const std::shared_ptr<book>& book, const Point &point) const
{
return book->point < point;
}
};
And you would use it like this:
int main()
{
std::set<std::shared_ptr<book>, CompareBook> set_list;
std::deque<std::shared_ptr<book>> list;
std::shared_ptr<book> book1 = std::make_shared<book>(1, 1, std::string("Hello Kitty"));
std::shared_ptr<book> book2 = std::make_shared<book>(1, 2, std::string("C++ Bible"));
list.push_back(book1);
list.push_back(book2);
set_list.insert(book1);
set_list.insert(book2);
auto it = set_list.find(Point{1,1});
if (it != set_list.end())
{
std::cout << (*it)->name;
}
return 0;
}
Here's a demo.
Final word of caution: even though you can access the same element in the deque and set via the pointer, you should avoid changing the fields that take part in ordering, i.e. the x
and y
, to avoid messing up your set.