设计一个带有两个指向嵌套对象的指针的迭代器

时间:2019-05-19 04:56:12

标签: c++ algorithm design-patterns data-structures iterator

集装箱的目标

我正在构建一个容器,该容器用于以非常高效的RAM方式存储排序的无符号整数值。想法是按公用基数对值进行分组。代替

std::vector<unsigned int> V = {1234,1254,1264,1265,1267,1268,1271,1819,1832,1856,
                                  1867,1892,3210,3214,3256,3289};

我会有类似的东西

MyContainer V =
{
   {12..
      ..34, ..54, ..64, ..65, ..67, ..68, ..71
   },
   {18..
      ..19, ..32, ..56, ..67, ..92
   }
   {32..
      ..10, ..14, ..56, ..89
   }
};

在上面的示例中,我将值按100的块进行分组。将数据按2 ^ 16的组进行分组更合乎逻辑。假设每个unsigned int是4个字节,每个unsigned short是2个字节,则16个元素的第一个向量将至少占用16 * 4 = 64字节,第二个向量将占用19 * 2 = 38个字节RAM。

简要容器说明

简而言之,这是这个容器的组织...

class MyContainer
{
   // attribute
   std::vector<Block> data;

   // methods
   // ..
};

class Block
{
   // attributes
   unsigned short radix;
   std::vector<unsigned short> suffixs; // contains all the suffix associated with this radix

   // methods
   // ..
};

尽管欢迎提供有关此数据结构的建议,但我的问题的核心是关于迭代器的实现。

迭代器

构建迭代器时遇到问题。我的迭代器还需要允许进行正向探索和随机访问。这是我第一次构建经典的迭代器设计模式,并且我可能会犯错误。这是我的迭代器的属性

class Iterator
{
   // attributes
   std::vector<Block>::iterator bigP;             // points to a Block
   std::vector<unsigned short>::iterator smallP;  // points to an unsigned int within the Block pointed by bigP
   std::vector<Block>::iterator bigPEnd;

  // methods
  // ...
};

问题1:MyContainer::iterator应该包含迭代器(目前是这样)还是应该包含指针?为什么?

我认为,当迭代器指向unsigned int的最后一个Block时,operator++()应该将bigP推送到下一个Block并推送smallP

的第一个元素

对我来说似乎错误的是,我必须在data.end()中包含一个迭代器(称为bigPEnd),但是当我意识到operator++()被调用时, MyContainer::iterator指向最后一个unsigned int的最后一个Block,我必须知道无法将smallP设置为bigP->begin(),因为这会导致没有*bigP这样的分段错误。

问题2:我是否需要指向data的最后一个元素的指针?如何避免呢?

为空向量构建MyContainer::iterator时,我也面临类似的问题。通常,我会用

构造一个迭代器
MyContainer::iterator MyContainer::begin()
{
   return iterator(data.begin(), data.front().suffixs.begin(), data.end());
        //            ^^                 ^^                       ^^
        //           bigP              smallP                    bigPEnd
}

但是,当data.front()为空时,data将导致分段错误。如果使用指针,则可以在数据为空以及smallP数据是否为空时将nullptr设置为bigP == data.end()

问题3:在没有要指向的内容时,我该如何处理smallP

能否请您给我一些有关此迭代器实施的建议?

1 个答案:

答案 0 :(得分:1)

Q1

  

MyContainer::iterator应该包含迭代器(目前是这样)还是应该包含指针?为什么?

在性能和内存方面,使用指针还是迭代器都无关紧要。迭代器只是指针逻辑的面向对象的等效项。像所有面向对象的东西一样,它们旨在使代码更易于阅读和维护,即减少引入错误的机会。

如果您使用STL,也可以使用迭代器。它们是来自同一基本思想的两个概念-用面向对象的编程概念扩展C。与指针相比,使用迭代器也是一种行业标准。

第二季度

  

我是否需要指向data的最后一个元素的指针?如何避免呢?

您可以保存对vector的基础Block的引用,并通过引用获取结束迭代器。请参见下面的代码。这最好是保持恒定的最终值,因为如果在构造迭代器之后将新元素推回到vector的{​​{1}}中,则迭代不会中断。我没有在C ++文档中找到保证Block更改时vector::end()的值不变的保证。同样值得考虑的是,如果将来的代码版本中将vector更改为其他基础容器类型,将会发生什么情况。

Q3

  

在没有任何要指向的地方,我该如何处理vector

您可以将其保留不变,并将其称为未定义的值。此方法与标准库对未初始化的迭代器的方法一致-它们也具有未定义的值,不应取消引用。


您可以使用下面的示例进行操作,您会发现它很有帮助:

游乐场:https://ideone.com/eeAKYN

smallP

资源: