【问题标题】:Can I use std::sort on heap allocated raw arrays?我可以在堆分配的原始数组上使用 std::sort 吗?
【发布时间】:2019-05-13 15:57:47
【问题描述】:

我们知道,当使用一个连续的内存块时,我们可以很容易地获得一个迭代器(这里是 &arra[0]arra)并将迭代器传递给 std::sort。

例如:

int arra[100];
    for (int i = 0; i < 100; i++) {
        arra[i] = rand() % 32000;
    }
    for (int i = 0; i < len; i++)std::cout << arra[i]<<" ";
    std::sort(arra,arra+100);

现在,如果我有一个堆分配的数组,比如这里的arr

int len;
    len = 100;
    int* arr = new int[len];
    for (int i = 0; i < len; i++) {
        arr[i] = rand() % 32000;
    }

我不知道我是否可以得到这个数组的迭代器,那么我可以对这个数组使用 std::sort 吗? 如果没有,在这样的数组上使用 std::sort 是否有任何解决方法?

【问题讨论】:

  • 你没试过吗?
  • 不是一个精确的骗子,但有答案,试图找到一个更好的匹配:stackoverflow.com/questions/45123882/…
  • std::sort(arr, arr + len); 恕我直言,对于std::sort(),无论开始和结束是堆栈地址还是堆地址,都没有任何区别。在这种情况下,重要的只是连续存储。
  • 这里有一些相关信息:stackoverflow.com/questions/1719607/…

标签: c++ sorting memory-management heap-memory dynamic-arrays


【解决方案1】:

指针确实符合std::sort 要求的RandomAccessIterator 标准。它们指向堆栈内存还是堆内存并不重要,只要它们指向相同的(连续的)数组即可。所以你可以简单地使用:

std::sort(arr, arr + len);

话虽如此,std::vector 可能是在堆上分配数组的更好选择。它会让您免去自己管理内存的麻烦。

【讨论】:

  • 即使在堆分配中,arr+len 是否也指向数组的末尾?我的印象是,一旦你使用堆分配,内存就不再是一个连续的块,哎呀。我的错。 :P
  • 我对链表结构感到困惑。抱歉,我是新手
  • 别担心,每个人都已经从那里开始了 :) 是的,数组总是连续的,不管你是在堆上还是在栈上分配它。它是由标准保证的。有很多东西使用这个属性,例如运算符[]其实就是指针加法,所以array[5]*(array + 5)是一模一样的指令。
【解决方案2】:

是的,您可以在两种情况下以相同的方式使用std::sortstd::sort 不知道也不关心内存是如何分配的。

【讨论】:

    【解决方案3】:

    在 C++ 库中,迭代器基本上是花式指针。因此,将指针递增到数组末尾以获得“end”指针是符合标准的:

    #include<algorithm>
    #include<iostream>
    
    int main() {
        int len;
        len = 100;
        int* arr = new int[len];
        for (int i = 0; i < len; i++) {
            arr[i] = rand() % 32000;
        }
        //Valid, Defined Behavior that works as expected
        std::sort(arr, arr + len);
        //alternative, to make the code easier to read:
        //auto begin = arr;
        //auto end = arr + len;
        //std::sort(begin, end);
        for(int i = 0; i < len; i++)
            std::cout << arr[i] << std::endl;
    }
    

    但是,一些编译器(如 Visual Studio 的编译器)认识到这种代码本质上是不安全的,因为您需要手动提供数组的长度。因此,如果您尝试这样做,它们将导致(如果需要,可以使用 Compiler 标志抑制)编译时错误,并建议您改用编译器提供的实用程序:

    #include<algorithm>
    #include<iostream>
    
    int main() {
        int len;
        len = 100;
        int* arr = new int[len];
        for (int i = 0; i < len; i++) {
            arr[i] = rand() % 32000;
        }
    
        //MSVC Specific Code!
        auto begin = stdext::make_checked_array_iterator(arr, len);
        auto end = arr + len;
        std::sort(begin, end);
        for(int i = 0; i < len; i++)
            std::cout << arr[i] << std::endl;
    }
    

    有关此 Visual Studio 编译器的特别快速的更多信息,请参阅此处:https://docs.microsoft.com/en-us/cpp/standard-library/checked-iterators?view=vs-2019

    【讨论】:

      【解决方案4】:

      我可以在堆分配的原始数组上使用 std::sort 吗?

      是的。

      不知道能不能得到这个数组的迭代器

      你可以。

      指向元素的指针是数组的随机访问迭代器。在自动数组的情况下,数组名称隐式衰减为一个指针,您可以将其用作数组开头的迭代器。在动态数组的情况下,new[] 的结果已经是一个指针,即指向数组开头的迭代器。您可以使用指针算术将指针指向末尾,就像在您的示例中一样。

      在使用std::sort 时,数组变量和指向动态数组的指针之间的唯一显着区别是,您不能像使用数组变量那样将std::endstd::size 与指针一起使用。相反,您需要单独知道数组的大小。在这种情况下,您已将长度存储在变量 len 中。

      【讨论】:

        猜你喜欢
        • 2013-01-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-08-10
        • 1970-01-01
        • 2014-10-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多