如何删除const_iterator的constness?

aJ.*_*aJ. 43 c++ iterator stl const-iterator

作为扩展到这个问题const_iterators更快?,我有另一个问题const_iterators.如何删除一个常量const_iterator?虽然迭代器是指针的通用形式,但仍然const_iteratoriterators是两个不同的东西.因此,我相信,我也不能用来const_cast<>转换const_iteratoriterators.

一种方法可能是您定义一个迭代器,该迭代器将元素移动到该const_iterator点的元素.但这看起来像是一个线性时间算法.

对于实现这一目标的最佳方法有什么想法吗?

Jam*_*lis 68

在C++ 11中有一个具有恒定时间复杂度的解决方案:对于任何序列,关联或无序关联容器(包括所有标准库容器),可以使用空范围调用range-erase成员函数:

template <typename Container, typename ConstIterator>
typename Container::iterator remove_constness(Container& c, ConstIterator it)
{
    return c.erase(it, it);
}
Run Code Online (Sandbox Code Playgroud)

范围擦除成员函数有一对const_iterator参数,但它们返回一个iterator.由于提供了空范围,因此对erase的调用不会更改容器的内容.

向霍华德·辛纳特和乔恩·卡尔布提示这个技巧.

  • @xeo:嗯,当然.如果你可以在没有对容器的非const引用的情况下这样做,那将是const安全性的一个巨大漏洞. (7认同)
  • 但是,您需要访问容器. (2认同)
  • +1.Ultra-pedantry:这适用于所有标准容器,因为所有标准容器都是序列或关联容器或无序关联容器.但是`erase`实际上并不是容器需求的一部分,因此它不一定适用于满足容器需求的所有用户定义类型.你已经在答案中说过这一点了,但在parens的列表中添加了"无序关联".也许这种迂腐应该适用于你对Visage答案的评论,你说"所有容器",而不是你的完整答案. (2认同)

Pau*_*ams 14

不幸的是,线性时间是唯一的方法:

iter i(d.begin());
advance (i,distance<ConstIter>(i,ci));
Run Code Online (Sandbox Code Playgroud)

其中iter和constIter是合适的typedef,d是你要迭代的容器.

  • 允许实现(并且确实)为随机访问迭代器专门化std :: advance和std :: distance,这样对于某些容器来说这可以是恒定的时间. (5认同)
  • 实际上,这应该是(良好实现的)随机访问迭代器的恒定时间.见http://www.aristeia.com/Papers/CUJ_June_2001.pdf. (5认同)

Dav*_*eas 5

在您上一篇文章的答案中,有几个人(包括我)出于与性能无关的原因建议使用 const_iterators 。从设计板到代码的可读性、可追溯性……使用 const_iterators 提供对非常量元素的变异访问比根本不使用 const_iterators 要糟糕得多。您正在将代码转换为只有您才能理解的东西,并且设计更糟糕,并且真正的可维护性痛苦。仅仅使用 const 来抛弃它比根本不使用 const 更糟糕。

\n\n

如果你确定你想要它,C++ 的好处/坏处是你总能找到足够的绳子来吊死自己。如果您的目的是使用 const_iterator 来解决性能问题,那么您确实应该重新考虑它,但如果您仍然想放弃……那么 C++ 可以提​​供您选择的武器。

\n\n

首先,最简单的:如果您的操作将参数作为 const (即使内部应用 const_cast),我相信它应该直接在大多数实现中工作(即使它可能是未定义的行为)。

\n\n

如果您无法更改函子,那么您可以从任一方面解决问题:在 const 迭代器周围提供一个非常量迭代器包装器,或者在非常量函子周围提供一个 const 函子包装器。

\n\n

迭代器 fa\xc3\xa7ade,漫长的道路:

\n\n
template <typename T>\nstruct remove_const\n{\n    typedef T type;\n};\ntemplate <typename T>\nstruct remove_const<const T>\n{\n    typedef T type;\n};\n\ntemplate <typename T>\nclass unconst_iterator_type\n{\n    public:\n        typedef std::forward_iterator_tag iterator_category;\n        typedef typename remove_const<\n                typename std::iterator_traits<T>::value_type\n            >::type value_type;\n        typedef value_type* pointer;\n        typedef value_type& reference;\n\n        unconst_iterator_type( T it )\n            : it_( it ) {} // allow implicit conversions\n        unconst_iterator_type& operator++() {\n            ++it_;\n            return *this;\n        }\n        value_type& operator*() {\n            return const_cast<value_type&>( *it_ );\n        }\n        pointer operator->() {\n            return const_cast<pointer>( &(*it_) );\n        }\n        friend bool operator==( unconst_iterator_type<T> const & lhs,\n                unconst_iterator_type<T> const & rhs )\n        {\n            return lhs.it_ == rhs.it_;\n        }\n        friend bool operator!=( unconst_iterator_type<T> const & lhs,\n                unconst_iterator_type<T> const & rhs )\n        {\n            return !( lhs == rhs );\n        }\n    private:\n        T it_;  // internal (const) iterator\n};\n
Run Code Online (Sandbox Code Playgroud)\n