使用C++11的std::sort和lambda函数对动态分配的多维C数组进行排序

4

我正在尝试使用lambda编写自定义排序函数,并使用std::sort对一个动态分配的二维数组进行排序。程序启动时确定了一个整数值numFaces,在程序生命周期内不会改变。这是我的当前方法。

float(*data)[24] = new float[numFaces][24];
std::sort(data, data + numFaces,  [](float (&A)[24], float (&B)[24]) -> bool
{
    return comparison(A, B); // Pseudo
});

该程序出现以下错误无法编译:

数组类型'float [24]'不可分配

由于我在lambda声明中指定参数应为引用,所以我不明白为什么编译器会产生这个错误消息。我正在使用Microsoft的Visual Studio Community Edition 2015中的VC++编译器。这里是整个日志的快速pastebin
第38行是lambda函数声明的闭合括号。
我知道我可以用几种不同的方法解决这个问题,但如果有一种方法可以使其工作,我希望继续像这样进行。如果您对另一种解决方案有建议,可以让数据按这些组的28个浮点数存储并排序,我将非常高兴听到这一点。
我可以解决当前问题的方式,这将引入其他问题和/或更大的应用程序延迟:
  • 使用具有void指针的qsort,将它们强制转换并以基本相同的方式进行排序。我有点不确定是否会在std::sort没有关于容器的所有信息时引入任何延迟,如果我使用std::vectors。
  • 使用嵌套的std::vectors进行std::sort。数据不总是存储在内存上,这反过来会强制我每次对向量进行排序时创建数据的副本。我测试了这一点,并使用VS调试器检查了内存位置,但我不确定是否可以通过某种方式解决。
  • 使用具有所需数据的自定义类/结构的std::vector。如果没有简单的解决方案来解决我的问题,我将执行此操作或在没有任何STL调用的情况下进行排序。
小提示:上面代码标签中的代码已剥离了不必要的代码。 pastebin由于此原因略有不同。
快速回顾问题及其解决方案: std::sort通过分配一个元素到另一个元素重新排列您正在排序的任何内容的元素。由于这个原因,元素必须是可分配的,而C风格的数组根本不是。有许多方法可以解决这个问题,但如果您需要数据在内存上连续存储,则需要一个准确包含数组将要包含的数据的类型;没有更多,也没有更少。正如评论中的人们指出的那样,std::array是完美的类型。以下是示例解决方案:
#include <vector>
#include <array>

std::vector<std::array<float, 24>> data;

使用以下 std::sort 调用:

std::sort(data.begin(), data.end(), [](const std::array<float, 24> &A, const std::array<float, 24> &B) -> bool
{
    return A[0] < B[0]; // Sample sort condition
});

对于提供有效解决方案的人加1分,对于仅部分重新实现std::array的人减1分 :) (说真的,请查看std::array,它是与上述结构相比更通用和完整的实现) - mkal
这是排序过程的快速GIF。它运行得非常好。imgur.com/iPNSBmJ - Hooder
我能记得的只是它有一些奇怪的错误信息。在定义为array<float, 24>时却出现了“未知大小”。不过我敢打赌,我可以想办法让它工作起来。 尽管数据在std::array中是连续存储的,但您确定它没有比那更多的数据吗?如果除了数组之外还有其他东西,数据将不再打包在外部向量中,并且指向向量中第一个浮点数的指针将无法读取数据。我在OpenGL中使用这个功能方便地将浮点数加载到缓冲区中。 - Hooder
1
“是的,我确定在std::array中除了数据之外没有其他对象。”(http://en.cppreference.com/w/cpp/container/array)。如果你遇到了错误,那么你肯定犯了一些错误。`std::array`的接口是`faceData`的超集。 - mkal
@mkal 感谢你的所有帮助。我不记得为什么之前使用 std::array 无法正常工作,但这次我写出来就可以了。我已经更新了示例解决方案以使用 std::array,并且它以完全相同的速度运行,并带来了 std::array 类所带来的所有附加好处。 - Hooder
显示剩余2条评论
1个回答

5

首先,基础知识:

float(*data)[24] = new float[numFaces][24];

在这里,你将data定义为大小为numFaces的动态数组,每个元素是静态大小的24数组,这意味着data [0]是大小为24的数组,data [1]是大小为24的数组,以此类推。

因此,使用std::sortdata进行排序,意味着对其元素进行排序-data [0] data [1] data [2] 、...、data [numFaces-1] -它们本身是静态大小的数组。

由于我在lambda声明中指定了参数应该是引用类型,所以我不知道编译器为什么会生成这个错误消息。

错误是因为在C++(和C)中,数组不可赋值,就像错误消息明确说明的那样。为了对元素进行排序,std::sort 需要重新排列元素,而这只能通过赋值来完成——库没有使用其他方法。它使用迭代器,在某些地方执行以下操作:

 *it1 =  *it2;   //it1 and it2 point to arrays

这基本上相当于这个:

data[i1] = data[i2];  

由于data [i1]是一个(静态)大小为24的数组,因此上述赋值是无效的。如果您这样做,将会得到相同的错误:

float a[24], b[24];

a = b; //error

希望能帮到您。

哦,现在的错误信息比之前更有意义了。非常感谢。我之前尝试使用一维数组解决这个问题,但无法想出不对每个浮点数进行排序的方法。您有什么建议吗? - Hooder
3
@Whitehooder,std::array<float, 24>的对象是可分配的,不同于“常规”数组。那么,这些的动态数组是否符合您的要求?语法可能更易于理解… using Face = std::array<float, 24>; - mkal
@mkal,我确实尝试过那种方法,但它似乎有一些相同的问题和限制。最终,我创建了一个包含24个浮点数数组的结构体,并重载了赋值运算符,使用基本循环设置了数组的所有值,就像我最初认为STL所做的那样。现在它运行得很好,我已经开始优化排序函数了。感谢您的所有建议。 - Hooder
1
正如其他人所说,std::array解决方案无法工作只意味着您犯了不同的错误,而不是std::array是错误的。 - Yakk - Adam Nevraumont
@Yakk,我明白了。最终我会再仔细研究一下,并在更新时提供更好的解决方案。 - Hooder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接