简体   繁体   English

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

[英]How can I avoid using a const_cast with std::vector::erase() in C++?

I have a class like this: 我有一个这样的课:

  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();
  }

Apparently, std::vector::erase() cannot take a const_iterator , but std::find() requires one. 显然, std::vector::erase()不能使用const_iterator ,但std::find()需要一个。 I could cast away the const -ness of the iterator returned by std::find() when feeding it to std::vector::erase() , but Effective C++ taught me to regard const_cast with suspicion. 在将它提供给std::vector::erase() ,我可以抛弃std::find()返回的迭代器的const ,但Effective C ++教会我怀疑const_cast

Is there another way to do this? 还有另一种方法吗? I can't believe that something as common as removing an element from a vector should require type gymnastics. 我无法相信从向量中移除元素这一常见的东西应该需要类型体操。 :) :)

I suggest you change or overload your _iterator_for_node() function to accept a non-const reference to the list. 我建议您更改或重载_iterator_for_node()函数以接受对列表的非const引用。 The reason std::find returns a const_iterator is because the list itself is const , and therefore begin() and end() return const_iterator s. std::find返回const_iterator的原因是因为列表本身是const ,因此begin()end()返回const_iterator

As an aside, const_cast<> won't actually convert a const_iterator to an iterator as the 'const' is just part of the name, not a CV-qualifier. const_cast<>一句, const_cast<>实际上不会将const_iterator转换为iterator因为'const'只是名称的一部分,而不是CV限定符。

Also, you're not technically supposed to prefix names with an underscore, as this is reserved for implementations. 此外,从技术上讲,您不应该使用下划线为名称添加前缀,因为这是为实现保留的。 (it will generally work in practice) (它通常会在实践中工作)

Aside from my direct modification of the code , here's an idea: 除了我对代码的直接修改 ,这里有一个想法:

Instead of a member function _iterator_for_node which 而不是成员函数_iterator_for_node

  • has const issues 有const问题
  • is uselessly tightly bound to a particular container type (inducing a typename template resolution mess) 无用地紧紧绑定到特定的容器类型(导致typename模板解决方案混乱)
  • does nothing more than std::find and throw an exception if not found 什么都不做比的std ::多发现抛出一个异常,如果没有找到

I suggest creating the following static (global/namespace) function instead: 我建议改为创建以下静态(全局/命名空间)函数:

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();
}

It will work with any iterator type (including non-STL, input stream iterators, forward only, const, reverse iterators... you name it) and it doesn't require explicit distinction between const/non const versions :) 它将适用于任何迭代器类型(包括非STL,输入流迭代器,仅转发,const, 反向迭代器......你的名字),它不需要显式区分const /非const版本:)

With it, 用它,

a working version of your code sample would just read 您的代码示例的工作版本只会读取

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)); }
};

Note the code reduction. 请注意代码缩减。 Always the good sign 总是好兆头

Cheers 干杯

There seems to be quite some confusion between const elements, and const iterators in your code. const元素和代码中的const迭代器之间似乎存在很多混淆。

Without looking in to the use case, I propose the following 'fix' to make things compile: 在没有查看用例的情况下,我建议使用以下“修复”来编译:

#include <algorithm>
#include <vector>
#include <iostream>

using namespace std;

struct NoSuchNodeException {};

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

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

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

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

    throw NoSuchNodeException();

}

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

    throw NoSuchNodeException();
}

int main()
{
    AdjacencyList<int> test;
    test.delete_node(5);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM