【问题标题】:How to construct a custom const_iterator with const data?如何使用 const 数据构造自定义 const_iterator?
【发布时间】:2011-12-12 20:30:54
【问题描述】:

我正在为自定义容器(一些哈希映射类)编写迭代器类,我们称这个容器为Map

出于几个原因,从const_iterator 派生iterator 似乎很方便,而且我已经在其他一些自定义容器(数组类)中这样做了,效果很好,所以我想坚持这种模式。

但是现在这导致了以下问题(很笼统/抽象,对不起):

无论const_iterator 的关键数据成员是什么(可能是Map 引用,或指向Map::Elements 的指针,有多种可能),它必须是非常量 所以const_iterator 和派生的iterator 都可以在他们的方法中有意义地利用它。

但是在处理 const Map 对象(例如调用方法 const_iterator Map::Begin( void ) const)时,如何以适当的方式初始化这个非常量数据成员?


为了说明我的问题,我编写了一些示例代码,通过使用 const_cast 来解决问题,我认为这是不好的风格:

#include <vector>

template< typename K, typename T >
class Map
{
public:
    class const_iterator
    {
    public:
        const_iterator( Map const & a_Map, int a_Index ) : 
            m_Index( a_Index ),
            m_Map( const_cast< Map & >( a_Map ) )  // Note the use of const_cast
        {
        }
    private:
        Map & m_Map;
        int   m_Index;
    };
    class iterator : public const_iterator
    {
    public:
        T & operator * ( void )
        {
            return m_Map.mElements[ m_Index ];
        }
    };
public:
    const_iterator Begin( void ) const { return const_iterator( *this, 0 ); }
    iterator       Begin( void )       { return       iterator( *this, 0 ); }
private:
    std::vector< T > m_Elements;
};

【问题讨论】:

  • 典型的迭代器实际上根本不包含所谓的“关键数据成员”。现实生活中的(发布)迭代器和它所引用的容器之间通常没有任何联系。
  • 我知道这可能是出于学术好奇心,但有一个 std::map 可能会比 std::vector 被包装到自定义地图中表现更好。
  • @Kerrek SB 你完全正确。无论如何,这只是一个示例,“关键数据成员”可以是任何东西(例如,指向提供迭代器的 Map 的 m_Elements 中的第一个元素的指针)。无论我使用什么方法,问题总是一样的。

标签: c++


【解决方案1】:

当我过去玩这个时,我说服自己继承不是一个好主意。虽然iteratorconst_iterator 可能共享很多代码,但它们在界面中并没有真正共享太多。

相反,我使用模板来重用代码,因此iteratorconst_iterator 只是同一模板的两个版本。提供适当的隐式转换运算符。

但是如果你坚持继承模型,并且不希望你的迭代器有自己的非常量引用(即它的构造函数初始化它的非常量版本和基类的常量版本),那么const_cast我认为是唯一真正的选择。

【讨论】:

  • 谢谢!所以如果 const_cast 是唯一的选择(除了放弃继承)我可以忍受它。
  • 顺便说一句,您可能需要一个指针成员,而不是引用成员。想想拥有const iterator 类型的东西意味着什么。例如int *const 的行为方式。
  • 另外,我想确保您了解做这种事情的后果。其他人阅读您的代码(或 在 6 个月后阅读您的代码)可能会感到困惑。它可以破坏容器所做的优化,使const 版本比非const 版本更快。它也可能会阻止编译器进行优化。
  • 你是什么意思,有什么令人困惑的地方,为什么它会破坏优化?
  • 我曾经将一个计算密集型例程的性能提高了一倍,只是通过完全正确的const。是的,这是一个相当极端的情况,但它确实表明它确实有助于编译器。此外,源代码级别的优化也可以出现——例如dynamic_bitset::operator[] 的 const 版本(或 C++98 vector&lt;bool&gt;)比非 const 版本简单得多。可以想象非常量版本需要更多开销的容器!
猜你喜欢
  • 2014-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多