【问题标题】:Calling erase with iterator vs const_iterator使用迭代器与 const_iterator 调用擦除
【发布时间】:2011-06-20 14:18:50
【问题描述】:

为什么用const_iterator调用容器的erase成员函数会失败?

它适用于非 const iterator

【问题讨论】:

  • 例如,因为这是一个 const_iterator ?
  • 你究竟是如何defile迭代器的?可怜的东西:)
  • 这个问题似乎被认为是当前标准的缺陷。在 C++0x erase 标准容器的成员函数中采用 const_iterator。

标签: c++ data-structures


【解决方案1】:

这不会编译,因为 container::iteratorcontainer::const_iterator 是两种不同的类型,唯一(一个参数)版本的擦除是:iterator erase(iterator);

不接受const_iterator 可以被视为语言标准中的缺陷:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2350.pdf

这种限制没有特别的原因。迭代器仅用于在(可修改的)容器中指示位置,在inserterase 的情况下都不是被修改的迭代器的“指针”(在@987654328 的情况下) @ 它只是在概念上不复存在,这对于 const 对象来说是很正常的事情)。

当前标准表明“迭代器常量和容器常量”之间存在混淆(此处的其他答案也是如此),并且似乎 const_iterator 在 C++0x 中可能会被 erase 接受。


作为一种解决方法,您可以从const_iterator 有效地获取iterator,因为容器首先必须是可变的。

下面的函数只能为随机访问迭代器编译,因为它可能对其他类型的迭代器来说太慢了。

#include <vector>

template <class Container>
typename Container::iterator to_mutable_iterator(Container& c, typename Container::const_iterator it)
{
    return c.begin() + (it - c.begin());
}

int main()
{
    int arr[] = {1, 5, 2, 5, 3, 4, 5, 1};
    std::vector<int> vec(arr, arr + sizeof(arr) / sizeof(*arr));
    for (std::vector<int>::const_iterator it = vec.begin(); it != vec.end(); ) {
        //if (*it = 5) {  //const_iterator prevents this error
        if (*it == 5) {
            it = vec.erase(to_mutable_iterator(vec, it));
        }
        else {
            ++it;
        }
    }
}

但是,重组代码可能会更好,这样一开始就不需要const_iterator。在这种情况下,最好使用std::remove 算法。如果您需要在擦除之前做更多非变异工作,您可以将其提取到单独的方法等中。

【讨论】:

  • 毫无价值,因为 C++11 erase 确实对 const_iterator 有重载。
【解决方案2】:

我只想强调 UncleBens、David Rodriguez 和 Ise Westeria 发布的答案/cmets 的总体正确性。

无论当前(或以前)C++11 之前的编译器的行为如何,const_iterator 的 const 正确性(应该)在语义上等于 const T*(或 T* const)时立即停止 - 请注意T 本身可能是它自己的 const 类型! - 所以它有效地防止代码修改容器中的引用对象。

但是,由于在 C++ 中“删除”一个 const 指针是完全合法的(试试吧,它有效!),它应该是合法的(并且该行为已在 C++11 中更正)以及“擦除” " 来自容器的 const 迭代器,前提是容器本身不是 const。

似乎 Visual Studio 2010 已经通过让 'erase' 接受 const_iterator 来正确运行,这当然让我在寻找其他一些错误时有些头疼,这导致我写了这篇文章,最终澄清了“erase”的正确行为const_iterator" const 正确性。

【讨论】:

    【解决方案3】:

    关于常量,您可以将std::container&lt;T&gt;::const_iterator 视为const T*

    【讨论】:

    • 既然你对最初的问题很挑剔,我会对答案很挑剔:P,“但我可以deleteconst T*”。说真的,我不认为这个问题增加了太多价值,访问包含的元素是const这一事实并不一定意味着您不能修改容器本身。
    • @David:我只是想我会提到const T*,因为许多初学者似乎认为const_iterator 实际上更像T* const
    【解决方案4】:

    const_iterator 类型不能用于修改元素或容器的值。

    【讨论】:

    • 我同意。所以没有办法用 const_iterator 擦除条目?
    • 是的。这就是const_iterator 的用途。只授予访问权限,但没有修改权限。
    • 有趣的是,至少在 C++0x 的 N3092 中,容器的擦除和插入方法确实采用 const_iterator - 没有特别的理由说明为什么不适合这些方法,除了可能实现它们可能需要的const_casthackery。只要容器是可修改的,我就不会修改引用的项目,我只是使迭代器无效(const_iterator 一直发生这种情况)。
    • 删除与C++中的修改不同。
    猜你喜欢
    • 2016-11-11
    • 2014-02-21
    • 2013-04-05
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-02
    相关资源
    最近更新 更多