Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何有效地使用std::sort和不透明数据类型?_C++_Sorting_Stl - Fatal编程技术网

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

C++ 如何有效地使用std::sort和不透明数据类型?,c++,sorting,stl,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

我正在开发一个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是一种不透明类型,我可以将其视为固定长度的二进制缓冲区+和相关的排序函数

现在,我想在将这些foo传递回客户机代码之前对它们进行排序。可能有许多foo,因此我必须实现外部排序,但我想使用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数组中,但我不想这样做,因为在实践中,Foo可能非常小,因此并行序列可以使用与Foo序列一样多的内存,我想最大限度地增加一次可以排序的指针数量

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


还是有更好的办法?我真的不想编写自己的排序实现,尽管这可能不会太难。

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

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

作为下一步,我将看看是否可以使用完整的类型信息进行内部排序。因为它是最优的

否则,将使用具有专门交换的pod块伪引用迭代器。如果性能测试证明进一步的优化是正确的,那么它将为大的指针和小的数据排序


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

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

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

作为下一步,我将看看是否可以使用完整的类型信息进行内部排序。因为它是最优的

否则,将使用具有专门交换的pod块伪引用迭代器。如果性能测试证明进一步的优化是正确的,那么它将为大的指针和小的数据排序


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

基于FooIter::GetFooSize()的不同实现可能是一种方法……基于FooIter::GetFooSize()的不同实现可能是一种方法……我不明白为什么字节交换会不好。您需要重新排列对象,以便复制内存(或指向它们的指针)。大体上,它实际上取决于不透明类型的实现。如果它们可以有效地交换,您就可以了。@pmr-I可能只是想得太多了,但是交换它们的理想方法是有一个足够大的临时缓冲区来容纳一个foo,memcpy a到它,memcpy b到a,然后memcpy临时缓冲区到b。如果按字节执行,则需要在循环中执行n个字节交换,其中n是FooIter::GetFooSize(),是的,但正如我所说的:如果必须执行操作,则需要执行该操作。临时缓冲区将是静态的(它也有,因为您不能交换不同类型的数据)。您可能可以执行(逐字异或交换)[但这是否真的能让它更快还有待观察。好吧,我认为实际的答案是自己实现排序,从而允许安全地使用曾经分配的临时缓冲区。但现在我考虑得更多,这真的是过早的优化。我不明白为什么字节交换会不好。你需要重新排列对象,以便你需要复制内存(或指向内存的指针)。总的来说,这实际上取决于不透明类型的实现。如果它们可以有效地交换,那就没问题了。@pmr-我可能只是想得太多了,但是交换它们的理想方法是有一个足够大的临时缓冲区来容纳一个foo,memcpy a到它,memcpy b到a,然后memcpy临时缓冲区到b。如果你这样做了byte-wise,您需要在循环中进行n字节交换,其中n是FooIter::GetFooSize(),是的,但正如我所说的:如果必须执行操作,则需要执行该操作。临时缓冲区将是静态的(它也是静态的,因为您无法交换不同类型的数据)。您可能可以执行(逐字异或交换)[但这是否真的能让它更快还有待观察。好吧,我认为实际的答案是自己实现排序,从而允许安全地使用曾经分配的临时缓冲区。但现在我考虑得更多,这确实是过早的优化。