为啥 std::remove 需要 const 版本的迭代器? [复制]

Posted

技术标签:

【中文标题】为啥 std::remove 需要 const 版本的迭代器? [复制]【英文标题】:Why std::remove takes const version of iterators? [duplicate]为什么 std::remove 需要 const 版本的迭代器? [复制] 【发布时间】:2015-05-14 15:34:32 【问题描述】:

我正在使用 Visual Studio 2013 编译非常简单的代码:

std::set<int> a 1, 2, 3 ;
std::remove(a.begin(), a.end(), 3);

我希望这不会出错,但我很惊讶。错误发出:

Error   1   error C3892: '_Next' : you cannot assign to a variable that is const    c:\program files (x86)\microsoft visual studio 12.0\vc\include\algorithm

这怎么可能? a 是一个非常量 std::set。 std::remove() 移动它的元素,看起来完全合法。

在 VS 2008 中,以下类似代码编译时没有错误:

std::set<int> a;
std::remove(a.begin(), a.end(), 3);

【问题讨论】:

【参考方案1】:

该集合是非常量的,但 set::begin()set::end() 返回一个 const_iterator。可以看到on cppreference。

我相信这是为了避免“局外人”能够交换元素,因为 set 的不变量之一是所有元素都已排序(这正是 std::remove 所做的,它移动元素以便您可以调用擦除之后,请参阅erase-remove idiom)

如果要删除元素,请使用erase 成员函数。

【讨论】:

是的,我注意到了这种行为。它与VS 2008不同。在VS 2008中,代码编译。 @Sheen 这是 C++ 标准本身的变化。 P.S.我不喜欢这种变化。您曾经能够制作带有关键部分的对象,只要您不更改密钥,您就可以根据需要修改对象的其余部分。不再允许这样做。 @MarkRansom - 有什么变化?我使用的所有编译器都拒绝std::remove(a.begin(), a.end(), 3),无论我告诉编译器编译的标准版本是什么。我怀疑这更像是 VS 2008(我不使用的编译器)不符合任何版本的标准。 @DavidHammen 我想我可能记错了。我所知道的是,我已经使用过几次这种模式,但很遗憾看到它消失了。【参考方案2】:

std::remove 适用于像 vectorlist 这样的线性容器,而不是像 set 这样的排序容器。 (考虑一下:remove 交换元素。交换 set 的元素甚至 意味着是什么意思?)

听起来你想要std::set::erase

【讨论】:

以上是关于为啥 std::remove 需要 const 版本的迭代器? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

std::remove_if 将“const type”作为“this”参数传递会丢弃 linux 上的限定符 [重复]

令人疑惑的 std::remove 算法

std::remove 和 boost::filesystem::remove 之间的区别?

std::remove_extent 可以用来做啥?

在 Delphi 中,为啥传递接口变量有时需要它是 const 参数?

为啥这个函子的 operator() 需要尾随 const 修饰符?