通过 <set> C++ 更新 <deque> 元素
update <deque> element by <set> C++
我想这样做,但我认为 set::iterator 不会 return 引用元素(只是元素的值)
双端队列列表内部
正面{A - B - C - D - E - F - G}背面
我通过这段代码得到了元素'C'
book& temp = list[2];
然后我将它插入到我的集合中 set_list
set_list.insert(temp);
在同一个本地函数中,我这样做
for (set<book>::iterator iter = set_list.begin(); iter != set_list.end(); iter++) {
if(*iter == C) // just for example, i can prove this is object C or not
const_cast<book&>((*iter).setName('T');
}
当我调试我的程序时,我发现 set_list 中的 'C' 的名称已更新为 'T',但是
'list'(deque) 中 'C' 的名称未更新为 'T'。
我该如何解决这个问题?
谢谢。
--- 编辑 ---
比较运算符
bool operator < (const book& v) const {
if (y == v.y) {
return x < v.x;
}
else {
return y < v.y;
}
}
首先,这段代码:
set_list.insert(temp);
即使您在 std::deque
中使用对对象的引用,也不会在您的集合中存储引用。由于 STL 容器 don't allow you to store references,当您插入集合时会生成对象的副本。但是,您可以在其中存储指针,并且使用指针可以避免在两个容器中进行复制。
您遇到的另一个问题是 std::set
returns 对于 set<T>::const_iterator
和 set<T>::iterator
的迭代器是 const 迭代器。这是有原因的:它是一个有序的容器。更改元素会影响排序,使 std::set
无效。在内部,它被实现为一棵红黑树,它不会知道您对键所做的更改。这就是你不应该这样做的原因。
但是,在您的情况下,每个 book
元素的 name
字段似乎不是键的一部分。因此可以在不影响排序的情况下对其进行更新。
要解决这两个问题,您可以将集合更改为以下类型:
std::set<std::shared_ptr<book>, CompareBook>
其中 CompareBook
是自定义比较器。使用共享指针,您可以在双端队列和集合中引用相同的 book
对象。
您还可以使比较器透明化,这意味着您可以通过在语义上是关键的东西来搜索书籍,即使它在技术上不是关键。在您的情况下, x
和 y
值。为了使事情更简单,您可以为封装这两个字段的键定义一个结构:
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;
};
把所有这些放在一起,你会得到一个像这样的比较器:
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;
}
};
你会像这样使用它:
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;
}
这是一个 demo。
最后一句警告:即使您可以访问双端队列中的相同元素并通过指针进行设置,您也应该避免更改参与排序的字段,即x
和 y
,以避免弄乱你的集合。
我想这样做,但我认为 set::iterator 不会 return 引用元素(只是元素的值)
双端队列列表内部
正面{A - B - C - D - E - F - G}背面
我通过这段代码得到了元素'C'
book& temp = list[2];
然后我将它插入到我的集合中 set_list
set_list.insert(temp);
在同一个本地函数中,我这样做
for (set<book>::iterator iter = set_list.begin(); iter != set_list.end(); iter++) {
if(*iter == C) // just for example, i can prove this is object C or not
const_cast<book&>((*iter).setName('T');
}
当我调试我的程序时,我发现 set_list 中的 'C' 的名称已更新为 'T',但是
'list'(deque) 中 'C' 的名称未更新为 'T'。
我该如何解决这个问题?
谢谢。
--- 编辑 --- 比较运算符
bool operator < (const book& v) const {
if (y == v.y) {
return x < v.x;
}
else {
return y < v.y;
}
}
首先,这段代码:
set_list.insert(temp);
即使您在 std::deque
中使用对对象的引用,也不会在您的集合中存储引用。由于 STL 容器 don't allow you to store references,当您插入集合时会生成对象的副本。但是,您可以在其中存储指针,并且使用指针可以避免在两个容器中进行复制。
您遇到的另一个问题是 std::set
returns 对于 set<T>::const_iterator
和 set<T>::iterator
的迭代器是 const 迭代器。这是有原因的:它是一个有序的容器。更改元素会影响排序,使 std::set
无效。在内部,它被实现为一棵红黑树,它不会知道您对键所做的更改。这就是你不应该这样做的原因。
但是,在您的情况下,每个 book
元素的 name
字段似乎不是键的一部分。因此可以在不影响排序的情况下对其进行更新。
要解决这两个问题,您可以将集合更改为以下类型:
std::set<std::shared_ptr<book>, CompareBook>
其中 CompareBook
是自定义比较器。使用共享指针,您可以在双端队列和集合中引用相同的 book
对象。
您还可以使比较器透明化,这意味着您可以通过在语义上是关键的东西来搜索书籍,即使它在技术上不是关键。在您的情况下, x
和 y
值。为了使事情更简单,您可以为封装这两个字段的键定义一个结构:
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;
};
把所有这些放在一起,你会得到一个像这样的比较器:
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;
}
};
你会像这样使用它:
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;
}
这是一个 demo。
最后一句警告:即使您可以访问双端队列中的相同元素并通过指针进行设置,您也应该避免更改参与排序的字段,即x
和 y
,以避免弄乱你的集合。