【问题标题】:Partially sort a C-style 2D array with std::sort使用 std::sort 对 C 风格的 2D 数组进行部分排序
【发布时间】:2020-09-12 01:25:40
【问题描述】:

我遇到this question 对整数数组的前两行进行排序,想到的明显方法是使用std::sort,因此我提出了如下解决方案:

int mat[][3] = { {4, 5, 3},
                 {6, 8, 7},
                 {9, 5, 4},
                 {2, 1, 3} }; 


std::sort(std::begin(mat[0]), std::end(mat[1])); //sprting the first two rows

您可以see here 工作,不会出现错误或警告。

同时 @Jarod42 pointed out that this is pedantically undefined behaviour 在 C++ 中,因为它们是两个不同数组的指针。

我倾向于这样做,因为在 C 中这将是一个很好的方法,(当然没有 std::sortstd::beginstd::end),使用类似的方法来访问数组,考虑到二维数组在 C 中的存储方式。

我们同意这是未定义的行为,but as @SergeBallesta remebered,几乎所有编译器都接受这种方法,所以应该使用它吗?

如果one uses a int(*mat)[3] pointer to array,这样使用std::sort 还是迂腐的UB?

//...
srand(time(0));

int(*mat)[3] = (int(*)[3])malloc(sizeof(int) * 4 * 3);
//or int(*mat)[3] = new int[4][3];

for(int i = 0; i < 4 ; i++)
    for(int j = 0; j < 3; j++)
        mat[i][j] = rand() % 9 + 1;

std::sort(std::begin(mat[0]), std::end(mat[1])); //sorting the first two rows
//...

【问题讨论】:

  • @anastaciu:可以检测到(至少在constexprhere)。糟糕的是,没有好的选择。并且编译器会做预期的事情(如果编译器将其视为 UB(将代码删除为错误的执行路径),那么确实需要警告来解决问题)。

标签: c++ arrays sorting c++11


【解决方案1】:

问题来自标准定义数组类型的方式(8.3.4 [dcl.array]):

数组类型的对象包含一个连续分配的非空集合,由 N 个类型为 T 的子对象组成。

但它并没有明确说明可以将一组连续分配的相同类型的对象用作数组。

出于兼容性原因,我知道的所有编译器都接受这种互惠,但从迂腐的角度来看,它没有在标准中明确定义并且是未定义的行为。

非互易性背后的基本原理是程序应该代表一个模型。而且在模型中,一个对象没有理由同时成为成员或多个数组。所以标准不允许。事实上,我遇到的所有(现实世界)用例都将 2D 数组当作 1D 数组处理,这只是低级优化原因。而在现代 C++ 中,程序员不应该关心低级优化,而是让编译器处理它。

以下仅代表个人观点。

当您发现自己像处理一维数组一样处理二维数组时,您应该问问自己原因。如果您使用的是遗留代码,请不要担心:编译器目前接受它,甚至将来可能会继续使用它,即使以特殊选项为代价。

但是,如果您正在编写新代码,您应该尝试上移(或后退)一步,并想知道它在模型级别代表什么。大多数时候,您会发现数组本质上是一维或二维的,但不是两者兼而有之。完成此操作后,如果性能不重要,请尝试始终以一致的方式处理它。或者更好的是,尝试使用标准库中的容器而不是原始数组。

如果您在性能关键代码中说任何连续分配的对象集是一个数组提供了重要的好处,请这样做并将其记录下来以供将来的维护者使用。但只有在分析之后才这样做......

【讨论】:

    猜你喜欢
    • 2018-11-20
    • 1970-01-01
    • 1970-01-01
    • 2011-08-19
    • 1970-01-01
    • 2012-11-03
    • 1970-01-01
    • 1970-01-01
    • 2016-11-20
    相关资源
    最近更新 更多