将const_iterator赋值给iterator

3
我有以下的代码片段(你可以在这里运行: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<std::pair<const int, const int> >_Rb_tree_iterator<std::pair<const int, const int> >没有已知的转换),这是预期的:
std::map<const int, const int>::iterator it  = myMap.cbegin();

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

如果你在std::map或者std::set前面加上const,我觉得你将无法完成你正在做的事情。你会得到一个编译器错误。 - santahopar
此外,你的const并不直接应用于你的向量或集合的元素,而是应用于你的std::pair中的元素,因此即使使用非const迭代器遍历你的向量,你仍然无法更改这些对的值。 - santahopar
3个回答

5
实际上,std::set<T>::iteratorstd::set<T>::const_iterator相同,因为std::set的元素是不可变的。它没有可变的迭代器类型。
这对于std::map来说并非如此,这就是你观察到不同行为的原因。

3

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

6 关联容器的迭代器属于双向迭代器类别。对于值类型与键类型相同的关联容器,迭代器和const_iterator均为常量迭代器。不确定迭代器和const_iterator是否为同一类型。


2
您不能修改集合的元素。键必须是const,以确保set所承诺的不变性:元素已排序且唯一。一个map的元素也是有序的,但您可以修改元素的映射值(键也是const)。std::map<A,B>的元素是std::pair<const A,B>
cppreference上,您可以阅读std::set的迭代器成员别名为:

iterator Constant LegacyBidirectionalIterator

const_iterator Constant LegacyBidirectionalIterator

它们都是常量迭代器。
另一方面,对于std::map,它们是:

iterator LegacyBidirectionalIterator

const_iterator Constant LegacyBidirectionalIterator

将一个const_iterator分配给非const的迭代器是错误的。这就像试图通过将指向const的指针分配给指向非const的指针来强制转换掉const一样。这是行不通的,因为你不能使不能被修改的东西变得可修改。这会破坏常量正确性。

从Vlad的回答中得知,std::setiteratorconst_iterator是否实际上是相同类型是未指定的。因此,尽管赋值在OP的平台上有效(因为它们是相同类型),但一般情况下是不正确的。 - François Andrieux
谢谢,修复了我最后一部分的问题,而且我没注意到(即使在阅读了答案之后也是如此 ;)) - 463035818_is_not_an_ai
谢谢你的评论,解释得很清楚!作为后续问题:在std::set中同时暴露iteratorconst_iterator是否有任何原因?只需要其中一个不就足够了吗? - Varun Hiremath
@VarunHiremath 容器被设计成通用的(不仅限于可以存储其中的元素)。您可以编写适用于容器的模板,并且您知道它们都具有iteratorconst_iterator - 463035818_is_not_an_ai

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接