【问题标题】:C++ Iterator range using pointers to an array使用指向数组的指针的 C++ 迭代器范围
【发布时间】:2019-09-19 13:56:09
【问题描述】:

问题

我不想将数组的大小作为索引参数传递。

对于我的merge_sort,我想使用迭代器范围概念优化我的参数。我似乎无法弄清楚如何尊重迭代器范围并访问我的数组。我可以在recursive_merge_sort 中访问像lowhigh 这样的索引,但似乎没有一种直观的方式来访问数组本身。我一直在使用C++ Pointers and Arrays 上的这个很棒的指南作为起点。

我的Merge Sort C++11 C++17 问题揭示了这个概念,我喜欢使用迭代器范围来减少排序参数数量的想法。

代码

void recursive_merge_sort(int* low, int* high) {
    // deference to get starting index "low" and ending index "high"   
    if(*(low) >= *(high) - 1) { return; }     

    int mid = *(low) + (*(high) - *(low))/2;

    // what's the correct syntax to access my array from the iterator range
    // int* d = some how deference low or how to get the data array they iterate on
    recursive_merge_sort_v(d + low, d + mid);
    recursive_merge_sort_v(d + mid, d + high);
    merge(d + low, mid, d + high);
    // delete d;
}

void merge_sort(int* data) {
    // what's the correct syntax to access my array from the passed in iterator range
    // is this event possible? incorrect syntax below
    recursive_merge_sort(data + 0, data + std::size(*(data)));
}

int main()
{
    int data[] = { 5, 1, 4, 3, 65, 6, 128, 9, 0 };
    int num_elements = std::size(data);

    std::cout << "unsorted\n";
    for(int i=0; i < num_elements; ++i) {
        std::cout << data[i] << " ";
    }

    merge_sort(data);

    std::cout << "\nsorted\n";
    for(int i=0; i < num_elements; ++i) {
        std::cout << data[i] << " ";
    }
}

评论部分来自河口的解决方案

Remy Lebeau:“当你通过指针传递一个数组时,你会丢失关于它的所有信息。你不能回到只给定指针/迭代器的原始数组,因为取消引用只会给你一个单一的元素数组,而不是数组本身。通过指针传递数组时,只能将数组大小作为另一个参数传递。否则,通过引用传递数组,如果需要支持不同大小的数组,则使用模板,以便编译器可以推断出引用的数组大小。”

【问题讨论】:

  • 将数组的大小作为额外参数传递。
  • Please read this SO post and answers,并阅读“合并排序”部分。您看到您的版本缺少比较两个通用项目的方法,而排序算法应该能够提供这种方法。
  • @0x499602D2 我想避免传入任何额外的参数,并希望使用迭代器来代替传入数组大小。
  • 当你通过指针传递一个数组时,你会丢失所有关于它的信息。仅给定指针/迭代器就无法返回原始数组,因为取消引用只会为您提供数组的单个元素,而不是数组本身。通过指针传递数组时,您别无选择,只能将数组大小作为另一个参数传递。否则,改为通过引用传递数组,如果您需要支持不同大小的数组,请使用模板,以便编译器可以推断出引用的数组大小。
  • @RemyLebeau 我将改用我之前的方法,感谢您的澄清,并感谢您在繁忙的日程中抽出时间处理 Fox Disney 的交易。

标签: c++ arrays pointers iterator


【解决方案1】:

迭代器被建模为像指针一样工作。它们具有相同类型的重载运算符:至少取消引用和递增(有些还具有递减、随机访问等)。

最高级的迭代器接口是随机访问,它的功能与原始指针完全一样(根据设计)。

所以所有(原始)指针基本上都是随机访问迭代器到 C 风格(连续)数组中。查看以下内容以可视化 C 样式数组的开始/结束迭代器:

int vals[] = { 0, 1, 2, 3, 4 };

int *begin = vals;
int *end   = vals + 5;
v vals[]
0   1   2   3   4   ...
^ begin             ^ end (1 past the end of array)

vals[2] == begin[2]
vals[4] == begin[4]
etc.

所以基本上,您只需将开始迭代器视为数组的前面,并且您不会在开始迭代器之前的任何位置取消引用,也不会在结束迭代器处或结束迭代器之后取消引用,因为标准 C++ 约定规定结束迭代器为 1超出范围的末尾。

这是一个使用迭代器等指针的示例:

void print(int *begin, int *end)
{
    // for each element in the range (starting at begin, up to but not including end)
    for (; begin != end; ++begin)
    {
        // print the element
        std::cout << *begin << '\n';
    }
}

int main()
{
    // declare a C-style array
    int arr[] = { 10, 5, 2, 6, 20 };

    // for the sake of example, print only the middle 3 elements
    // begin = arr + 1
    // end   = arr + 4
    print(arr + 1, arr + 4);

    return 0;
}

【讨论】:

  • 现在假设我将这样的迭代器int *end = vals + 5; 传递给一个函数,是否可以从*end 访问vals?还是我只能通过这样的参数访问结束索引5
  • @GregDegruy 好的,添加了一个打印迭代器范围内容的示例。这是否回答了您关于如何从迭代器范围访问元素的问题?
  • @GregDegruy 不,如果你的函数得到指针“end”指向的地址或值,你将没有整数5的信息,因此你不会知道C中的“vals” . 但是,你可以制作你自己的指针实现,它有一个 init 指针和一个偏移整数(例如 ptr *start = vals + 0 和 ptr *end = vals + 5),并将它传递到你喜欢的任何地方。这样您就可以使用单个“ptr”数据结构。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-04
  • 2019-08-24
  • 2014-10-13
  • 1970-01-01
  • 2019-01-24
  • 1970-01-01
相关资源
最近更新 更多