我正在构建一个容器,该容器用于以非常高效的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
?
能否请您给我一些有关此迭代器实施的建议?
答案 0 :(得分:1)
MyContainer::iterator
应该包含迭代器(目前是这样)还是应该包含指针?为什么?
在性能和内存方面,使用指针还是迭代器都无关紧要。迭代器只是指针逻辑的面向对象的等效项。像所有面向对象的东西一样,它们旨在使代码更易于阅读和维护,即减少引入错误的机会。
如果您使用STL,也可以使用迭代器。它们是来自同一基本思想的两个概念-用面向对象的编程概念扩展C。与指针相比,使用迭代器也是一种行业标准。
我是否需要指向
data
的最后一个元素的指针?如何避免呢?
您可以保存对vector
的基础Block
的引用,并通过引用获取结束迭代器。请参见下面的代码。这最好是保持恒定的最终值,因为如果在构造迭代器之后将新元素推回到vector
的{{1}}中,则迭代不会中断。我没有在C ++文档中找到保证Block
更改时vector::end()
的值不变的保证。同样值得考虑的是,如果将来的代码版本中将vector
更改为其他基础容器类型,将会发生什么情况。
在没有任何要指向的地方,我该如何处理
vector
?
您可以将其保留不变,并将其称为未定义的值。此方法与标准库对未初始化的迭代器的方法一致-它们也具有未定义的值,不应取消引用。
您可以使用下面的示例进行操作,您会发现它很有帮助:
smallP
资源: