C++ 在STL中将void*用作固定宽度记录

C++ 在STL中将void*用作固定宽度记录,c++,stl,C++,Stl,我有一个具有N条记录的连续缓冲区,每条记录宽W字节编译时N和W都是未知的。N*M是500mb的订单。我想在标准STL算法中使用它,比如sort()或nth_element()。我手头有一个比较仪。是否有任何已经实施的方法来做到这一点 到目前为止,我想出了两种方法: 1) 使用一个额外的向量,填充索引0…N,对其进行排序(使用自定义比较器),而不是对数据进行排序,使其按排序顺序类似于数据记录,然后根据该向量移动数据记录。缺点:额外的内存,修复数据记录顺序的额外困难,这有点不寻常 2) 创建一些自定

我有一个具有N条记录的连续缓冲区,每条记录宽W字节编译时N和W都是未知的。N*M是500mb的订单。我想在标准STL算法中使用它,比如sort()或nth_element()。我手头有一个比较仪。是否有任何已经实施的方法来做到这一点

到目前为止,我想出了两种方法:

1) 使用一个额外的向量,填充索引0…N,对其进行排序(使用自定义比较器),而不是对数据进行排序,使其按排序顺序类似于数据记录,然后根据该向量移动数据记录。缺点:额外的内存,修复数据记录顺序的额外困难,这有点不寻常


2) 创建一些自定义迭代器(知道W),它将返回一些类似于记录的临时“虚拟”类实例,并为该类重载swap(),以便它交换内存块。缺点:有点棘手,有点脆弱(需要遵循一些STL内部结构,例如将使用knowing swap()。

我选择第二种方法,但是通过提供自定义复制语义,而不是使用自定义的
swap
。使迭代器值类型成为一个类,该类包含一个
void*
成员,并具有复制该成员指向的记录的复制构造函数和赋值运算符。这不依赖于任何实现细节。

您的第二个选择——编写自定义迭代器——是一种可行的方法,效果非常好

您不需要依赖于正在使用的
swap
:您只需要重载代理对象的赋值运算符,当迭代器被取消引用时返回该运算符

(请注意,在C++11中,“交换”元素的算法和函数需要使用通过ADL找到的
swap
函数。不过,最好还是重载赋值运算符,尤其是在移动字节数组的情况下。)

我不知道有没有一个通用的实现,但作为一个起点,您可以从我的一个库(靠近文件底部)看一下。它包装一个字节数组,并覆盖算术运算符以一次将迭代器移动N个字节,其中N只在运行时已知。

我会投票支持选项2),但实际上不需要为存根类重载
swap()
。你只需要:

  • 创建迭代器返回的“存根”类
  • 实现分配宽度为W的内存块的默认ctor
  • 实现copyctor,它分配一个宽度为W的内存块,并复制输入内存块
  • 重载赋值运算符,以便将内存块从一个实例复制到另一个实例

这样,
swap()
将自动为您的类工作。

如果我没有swap(),则将使用默认的swap,即t=x,x=y,y=t。这样,我还需要支持代理中的临时存储,这似乎涉及到每次交换额外的分配W字节,这是大量的分配。另一方面,如果我重写swap(),我可以在没有这些额外alloc的情况下交换记录。最后,我的解决方案如下:我确实创建了一个自定义迭代器,它返回“Proxy”类对象,其中包含指向记录的指针。我实现了swap(),还实现了赋值构造函数/运算符。为了在未调用swap()时消除赋值中的大量分配,我还实现了一个带有原子锁的静态缓冲区(我确定在大多数情况下1个缓冲区就足够了)。当锁空闲时,使用预分配的缓冲区。当它忙时,内存会像往常一样分配。最后,swap()+单缓冲区在典型使用中将allocs减少到0。