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

时间:2011-04-20 08:02:15

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

显然,std::vector::erase()无法使用const_iterator,但std::find()需要一个const。在将std::find()提供给std::vector::erase()时,我可以抛弃const_cast返回的迭代器的{{1}} - 但Effective C++教会我怀疑{{1}}。

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

3 个答案:

答案 0 :(得分:7)

我建议您更改或重载_iterator_for_node()函数以接受对列表的非const引用。 std::find返回const_iterator的原因是因为列表本身为const,因此begin()end()返回const_iterator

另外,const_cast<>实际上不会将const_iterator转换为iterator,因为'const'只是名称的一部分,而不是CV限定符。

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

答案 1 :(得分:5)

除了my direct modification of the code之外,还有一个想法:

而不是成员函数_iterator_for_node

  • 有const问题
  • 无用地紧密绑定到特定的容器类型(引起类型名称模板解析混乱)
  • 除了std :: find 之外没有其他任何内容,如果找不到则会抛出异常

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

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

它将适用于任何迭代器类型(包括非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)); }
};

请注意代码缩减。总是好兆头

干杯

答案 2 :(得分:1)

const元素和代码中的const迭代器之间似乎存在很多混淆。

在没有查看用例的情况下,我建议使用以下'修复'来编译:

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