通过取消引用的迭代器访问 std::set

发布于 2025-01-15 16:24:31 字数 1766 浏览 0 评论 0原文

考虑:

#include <stdio.h>
#include <set>

void printset(std::set<int>& Set) {
    for (std::set<int>::iterator siter = Set.begin(); siter != Set.end(); ++siter) {
        int val = *siter;
        printf("%d ", val);
    }
}

void printsetofset0(std::set<std::set<int>>& SetofSet) {
    for (std::set<std::set<int>>::iterator siter = SetofSet.begin(); siter != SetofSet.end(); ++siter) {
        std::set<int> Set = *siter;
        printset(Set);
    }
}

void printsetofset1(std::set<std::set<int>>& SetofSet) {
    for (std::set<std::set<int>>::iterator siter = SetofSet.begin(); siter != SetofSet.end(); ++siter) {
        printset(*siter);//this line gives error
    }
}   

printsetofset1printset(*siter); 给出错误:

<source>: In function 'void printsetofset1(std::set<std::set<int> >&)':
<source>:20:34: error: binding reference of type 'std::set<int>&' to 'const std::set<int>' discards qualifiers
   20 |                         printset(*siter);
      |                                  ^~~~~~
<source>:4:38: note:   initializing argument 1 of 'void printset(std::set<int>&)'
    4 |         void printset(std::set<int>& Set) {
      |                       ~~~~~~~~~~~~~~~^~~
Compiler returned: 1

参见 Godbolt 链接 此处

printsetofset0 包含以下行: std::set;设置= *站点; printset(Set);

编译并工作得很好。

为什么一个 printsetofset0 可以工作,而看似功能相同(且更短)的 preintsetofset1 却不起作用?

Consider:

#include <stdio.h>
#include <set>

void printset(std::set<int>& Set) {
    for (std::set<int>::iterator siter = Set.begin(); siter != Set.end(); ++siter) {
        int val = *siter;
        printf("%d ", val);
    }
}

void printsetofset0(std::set<std::set<int>>& SetofSet) {
    for (std::set<std::set<int>>::iterator siter = SetofSet.begin(); siter != SetofSet.end(); ++siter) {
        std::set<int> Set = *siter;
        printset(Set);
    }
}

void printsetofset1(std::set<std::set<int>>& SetofSet) {
    for (std::set<std::set<int>>::iterator siter = SetofSet.begin(); siter != SetofSet.end(); ++siter) {
        printset(*siter);//this line gives error
    }
}   

printsetofset1 with the printset(*siter); gives error:

<source>: In function 'void printsetofset1(std::set<std::set<int> >&)':
<source>:20:34: error: binding reference of type 'std::set<int>&' to 'const std::set<int>' discards qualifiers
   20 |                         printset(*siter);
      |                                  ^~~~~~
<source>:4:38: note:   initializing argument 1 of 'void printset(std::set<int>&)'
    4 |         void printset(std::set<int>& Set) {
      |                       ~~~~~~~~~~~~~~~^~~
Compiler returned: 1

See Godbolt Link here.

printsetofset0 with the lines: std::set<int> Set = *siter; printset(Set);

compiles and works just fine.

What is the reason why one printsetofset0 works, while seemingly functionally equivalent (and shorter) preintsetofset1 does not work?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

孤寂小茶 2025-01-22 16:24:31

迭代器指向的元素是常量。您可以在注释中阅读:因为iterator 和 const_iterator 是常量迭代器(实际上可能是相同的类型),不可能通过任何这些成员函数返回的迭代器来改变容器的元素。。但是,传递对 printset 函数的引用会违反此属性。

在内部,集合允许通过索引结构进行快速访问。更改元素需要对集合重新排序(内部)。

您可以通过向 printset 函数的参数添加 const 修饰符来解决这种情况:

void printset(const std::set<int>& Set)

The elements, which the iterator points to, are constant. You can read it here in the Notes: Because both iterator and const_iterator are constant iterators (and may in fact be the same type), it is not possible to mutate the elements of the container through an iterator returned by any of these member functions.. But, passing a reference to your printset function would violate this property.

Internally, sets allow fast access via index structures. Changing the elements would require to reorder the set (internally).

You can solve the situation by adding a const modifier to the parameter of your printset function:

void printset(const std::set<int>& Set)
骄兵必败 2025-01-22 16:24:31

所有打印函数都应该通过 const 引用获取参数,因为它们不需要修改参数。像这样:

void printset(const std::set<int>& Set)

我还建议使用基于范围的 for 循环来简化您的代码:

for (int val : Set)

printset 无法采用非常量引用的原因是您将其传递给集合内的集合,并且集合中存储的值始终是 const。有关详细信息,请参阅:为什么std::set 似乎强制使用 const_iterator 吗?

All your print functions should take their argument by const reference, because they don't need to modify the argument. Like this:

void printset(const std::set<int>& Set)

I also suggest a range-based for loop to simplify your code:

for (int val : Set)

The reason printset cannot take a non-const reference is that you're passing it the set-within-a-set, and the values stored in sets are always const. For more on this, see: Why does std::set seem to force the use of a const_iterator?

画尸师 2025-01-22 16:24:31

问题是,尽管集合类型同时定义了 iteratorconst_iterator 类型,但这两种类型的迭代器都为我们提供了读取-仅访问集合中的元素。也就是说,集合中的键是 const。我们
可以使用集合迭代器来读取但不能写入元素的值。

因此,要解决程序中的错误,您需要向 printSet< 的名为 Set 的参数添加低级常量 /code> 功能如下图:

//------------vvvvv--------------------------->low-level const added here
void printset(const std::set<int>& Set) {
        //other code as before
    }

Demo

The problem is that although the set types define both the iterator and const_iterator types, both types of iterators give us read-only access to the elements in the set. That is, the keys in a set are const. We
can use a set iterator to read, but not write, an element’s value.

So to solve the error in your program you need to add a low-level const to the parameter named Set of the printSet function as shown below:

//------------vvvvv--------------------------->low-level const added here
void printset(const std::set<int>& Set) {
        //other code as before
    }

Demo

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文