如何避免在C++中使用带有std :: vector :: erase()的const_cast?

Jos*_*ver 4 c++ stl casting const

我有一个这样的课:

  template<class T>
  class AdjacencyList {
  public:
    void delete_node(const T&);

  protected:
    const typename std::vector<T>::const_iterator _iterator_for_node(
        const std::vector<T>&, const T&
    );
  };

  template<class T>
  void AdjacencyList<T>::delete_node(const T& node) {
    _nodes.erase(_iterator_for_node(_nodes, node));
  }

  template<class T>
  const typename std::vector<T>::const_iterator AdjacencyList<T>::_iterator_for_node(
      const std::vector<T>& list, const T& node
  ) {
    typename std::vector<T>::const_iterator iter =
        std::find(list.begin(), list.end(), node);
    if (iter != list.end())
      return iter;

    throw NoSuchNodeException();
  }
Run Code Online (Sandbox Code Playgroud)

显然,std::vector::erase()不能拿一个const_iterator,但std::find()需要一个.我可以抛弃它在const返回std::find()时返回的迭代器的性能std::vector::erase(),但有效的C++教会我const_cast怀疑.

还有另一种方法吗?我无法相信从向量中移除元素这一常见的东西应该需要类型体操.:)

pmd*_*mdj 7

我建议你改变或重载你的_iterator_for_node()函数来接受对列表的非const引用.究其原因std::find返回const_iterator是因为列表本身const,因此begin()end()返回const_iterator秒.

顺便说一句,const_cast<>实际上并不会转换const_iteratoriterator的"常量"只是名称的一部分,而不是一个CV-预选赛.

此外,从技术上讲,您不应该使用下划线为名称添加前缀,因为这是为实现保留的.(它通常会在实践中工作)

  • 因此,_iterator_for_node不是保留的,因为它是MEMBER函数(不在全局命名空间中),第二个字符不是大写字母或下划线. (3认同)
  • (N3291)17.6.4.3.2全局名称[global.names] 1某些名称和函数签名集始终保留给实现: - 每个名称包含双下划线_ _或以下划线开头,后跟大写字母(2.12)保留给任何用途的实施. - 以下划线开头的每个名称都保留给实现,以用作全局名称空间中的名称. (2认同)

seh*_*ehe 5

除了我对代码的直接修改,这里有一个想法:

代替一个成员函数的_iterator_for_node

  • 有const问题
  • 无用地紧紧绑定到特定的容器类型(引起typename模板解决方案的混乱)
  • 什么都不做比的std ::多发现抛出一个异常,如果没有找到

我建议改为创建以下静态(全局/命名空间)函数:

template<class It, class T>
    It checked_find(It begin, It end, const T& node)
{
    It iter = std::find(begin, end, node);
    if (iter != end)
        return iter;

    throw NoSuchNodeException();
}
Run Code Online (Sandbox Code Playgroud)

它将适用于任何迭代器类型(包括非STL,输入流迭代器,仅转发,const,反向迭代器......你的名字),它不需要显式区分const /非const版本:)

用它,

您的代码示例的工作版本只会读取

template<class T>
class AdjacencyList {
        std::vector<T> _nodes;
    public:
        void delete_node(const T& node) 
        { _nodes.erase(checked_find(_nodes.begin(), _nodes.end(), node)); }
};
Run Code Online (Sandbox Code Playgroud)

请注意代码减少.总是好兆头

干杯