通过 <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_iteratorset<T>::iterator 的迭代器是 const 迭代器。这是有原因的:它是一个有序的容器。更改元素会影响排序,使 std::set 无效。在内部,它被实现为一棵红黑树,它不会知道您对键所做的更改。这就是你不应该这样做的原因。

但是,在您的情况下,每个 book 元素的 name 字段似乎不是键的一部分。因此可以在不影响排序的情况下对其进行更新。

要解决这两个问题,您可以将集合更改为以下类型:

std::set<std::shared_ptr<book>, CompareBook>

其中 CompareBook 是自定义比较器。使用共享指针,您可以在双端队列和集合中引用相同的 book 对象。

您还可以使比较器透明化,这意味着您可以通过在语义上是关键的东西来搜索书籍,即使它在技术上不是关键。在您的情况下, xy 值。为了使事情更简单,您可以为封装这两个字段的键定义一个结构:

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

最后一句警告:即使您可以访问双端队列中的相同元素并通过指针进行设置,您也应该避免更改参与排序的字段,即xy,以避免弄乱你的集合。