【问题标题】: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);

【问题讨论】:

    标签: c++ visual-studio c++11 visual-studio-2013


    【解决方案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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-02-19
      • 2012-03-26
      • 1970-01-01
      • 1970-01-01
      • 2011-07-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多