【问题标题】:Assigning a const_iterator to an iterator将 const_iterator 分配给迭代器
【发布时间】:2021-02-11 05:21:28
【问题描述】:

我有下面的 sn-p 代码(你可以在这里运行:http://coliru.stacked-crooked.com/a/2f62134b5c125051

#include <iostream>
#include <set>
#include <map>

int main() 
{
    std::set<std::pair<const int, const int>> const mySet{{0,0}}; // value_type = std::pair<const int, const int>
    for (std::set<std::pair<const int, const int>>::iterator it  = mySet.cbegin(); it != mySet.cend(); ++it)
    {
        std::cout<<"set it = " << it->first << " " << it->second << std::endl;
    }

    std::map<const int, const int> const myMap{{0,0}}; // value_type = std::pair<const int, const int>
    for (std::map<const int, const int>::iterator it  = myMap.cbegin(); it != myMap.cend(); ++it)
    {
        std::cout<<"map it = " << it->first << " " << it->second << std::endl;
    }   
}

谁能解释一下为什么对于 std::set 下面没有抛出任何错误:

std::set<std::pair<const int, const int>>::iterator it  = mySet.cbegin();

而对于 std::map 下面会抛出错误(从 _Rb_tree_const_iterator<:pair int const> > _Rb_tree_iterator<:pair int const> >) 符合预期:

std::map<const int, const int>::iterator it  = myMap.cbegin();

std::set 是如何工作的?将 const_iterator 分配给 iterator 不应该总是抛出错误吗?

【问题讨论】:

  • 如果你把const 放在std::mapstd::set 前面,我不认为你能做你正在做的事情。你会得到一个编译器错误。
  • 另外,你的 const 并不直接应用于你的向量或集合的元素,它应用于你的 std::pair 中的元素,所以即使你的向量有一个非常量迭代器,你仍然无法更改对的值。

标签: c++ c++11 iterator set const-iterator


【解决方案1】:

实际上std::set&lt;T&gt;::iteratorstd::set&lt;T&gt;::const_iterator 相同,因为std::set 的元素是不可变的。它没有可变的迭代器类型。

std::map 不是这种情况,这就是您观察到不同行为的原因。

【讨论】:

    【解决方案2】:

    来自 C++ 17 标准(26.2.6 关联容器)

    6 关联容器的迭代器是双向的 迭代器类别。 对于值类型为的关联容器 与键类型相同,iterator 和 const_iterator 都是 常量迭代器。 未指定迭代器和 const_iterator 是同一类型。

    【讨论】:

      【解决方案3】:

      您不能修改集合元素。键必须是 const 以确保 set: 元素所承诺的不变量是有序且唯一的。 maps 元素也已排序,但您可以修改元素的映射值(键也是 const)。 std::map&lt;A,B&gt; 的元素是 std::pair&lt;const A,B&gt;

      cppreference 上,您可以看到std::set 的迭代器的成员别名是

      迭代器常量 LegacyBidirectionalIterator

      const_iterator 常量 LegacyBidirectionalIterator

      它们都是 const 迭代器。

      另一方面,std::map 他们是:

      迭代器 LegacyBidirectionalIterator

      const_iterator 常量 LegacyBidirectionalIterator

      const_iterator 分配给非常量是错误的。这就像试图通过将指向 const 的指针分配给指向非常量的指针来将 const 抛弃。它不起作用,因为您无法使无法修改的东西变为可修改的。这会破坏 const 正确性。

      【讨论】:

      • TIL 来自弗拉德的回答,如果 iteratorconst_iteratorstd::set 实际上是同一类型,则未指定。因此,虽然分配适用于 OP(因为它们在他们的平台上是相同的类型),但总的来说它是不正确的。
      • 谢谢,修复了我的最后一部分,但我没有注意到(即使在阅读了上述答案之后;)
      • 感谢您的评论,这就解释了!作为后续问题:是否有任何理由在std::set 中同时公开iteratorconst_iterator?难道只有一个就足够了吗?
      • @VarunHiremath 容器是通用的(不仅仅是关于您可以在其中存储哪些元素)。您可以编写适用于容器的模板,并且您知道它们都有 iteratorconst_iterator
      猜你喜欢
      • 2011-12-07
      • 1970-01-01
      • 2020-12-22
      • 2011-07-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-28
      • 2021-01-15
      相关资源
      最近更新 更多