如何有效地使用std :: sort与不透明数据类型?

时间:2013-02-23 23:19:34

标签: c++ sorting stl

我正在开发一个定义

等接口的SDK
class FooIter
{
    // Move to the next foo, return false if there is none.
    virtual bool Move() = 0;

    // Return a pointer to the current foo.
    virtual const void* GetFoo() = 0;

    // Get the size of a 'foo', which is a fixed-size POD.
    virtual size_t GetFooSize() = 0;

    // Get a comparator for foos.
    virtual const FooComparator* GetComparator() = 0;
};

class FooComparator
{
    virtual int compare(const void* first, const void* second) const = 0;
};

所以基本上,foo是一个opaque类型,我可以将其视为固定长度的二进制缓冲区+和相关的排序函数。

现在,我想在将这些foos传回客户端代码之前对它们进行排序。可能存在很多 foos,因此我将不得不实现外部排序,但我想使用std :: sort来对初始运行进行排序。

我想我会分配一个大小为N * FooIter :: GetFooSize()的缓冲区,使用FooIter填充foos,然后在将其写入磁盘之前使用std :: sort对其进行排序。

我可以从编写迭代器类

开始
class FooBufferIter
{
public:
    FooBufferIter(const void* fooAddr, int fooSize) : m_fooAddr(fooAddr), m_fooSize(fooSize) {}

    FooWrapper operator*() {return FooWrapper(m_fooAddr, m_fooSize);}

    FooBufferIter operator++() {return FooBufferIter(m_fooAddr + m_fooSize, m_fooSize);}

    // All other needed iterator methods.
private:
    const void* m_fooAddr;
    int m_fooSize;
};

和foo内存的包装类

class FooWrapper
{
public:
    FooWrapper(const void* fooAddr, int fooSize) : m_fooAddr(fooAddr), m_fooSize(fooSize) {}

private:
    const void* m_fooAddr;
    int m_fooSize;
};

我的理解是std :: sort将使用std :: swap来重新排列序列中的元素。我的问题是我无法看到如何在FooWrapper上专门化std :: swap来有效地执行交换(最重要的是,没有动态分配)。我可以逐字节交换,但这似乎效率低下。

另一种方法是将一个并行的指针序列排序到我的Foo数组中,但我不想这样做,因为在实践中,foos可能会非常小,所以并行序列可以使用和foo序列一样多的内存,我想最大化它一次可以排序的数量。

还有很好的'qsort'可能更适合这种事情,但我不确定如何将FooComparator对象转换为函数指针(可能有多个FooComparator实现)。

还是有更好的方法来解决这个问题吗?我真的不想编写自己的排序实现,虽然它可能不会很难。

1 个答案:

答案 0 :(得分:1)

我将构建一个void *的缓冲区,对它们进行排序,然后生成输出缓冲区。

作为第一步。因为容易。然后编写其他所有内容并寻找性能瓶颈。

下一步,我会看看是否可以完成具有完整类型信息的内部排序。因为最佳。

如果失败了,pod块伪引用迭代器与专门的交换。如果性能测试证明了进一步优化的合理性,那么对于小型med和大型的tomfoolery来说,它可以为大型和数据的小指针排序。

但从KISS开始,先做一些必须先硬的部分。