繁体   English   中英

stl::带原始指针的迭代器

[英]stl::iterators with raw pointers

我想对 C++ 数组使用迭代器,但也要使用原始指针。 我可以使用静态向量:

#define SIZE 10
int vect[SIZE] = {0};
vect[3] = 5;
int* p = std::find(std::begin(vect), std::end(vect), 5);
bool success = p != std::end(vect);

如何使用原始指针(可能是堆分配的向量)来做到这一点? 当然编译器不知道数据的大小,所以这段代码

int* pStart = vect;
std::find(std::begin(pStart), std::end(pStart), 5);

error C2784: '_Ty *std::begin(_Ty (&)[_Size])' : 
could not deduce template argument for '_Ty (&)[_Size]' from 'int *'

是否可以让begin()end()意识到它?

有可能让begin()和end()意识到它吗?

可以为指针实现std::begin ,但实现std::end是不可能的(因为正如你所说,大小未知),所以它有点无意义

但是,您不需要使用std::find

int* p = std::find(pStart, pStart + SIZE, 5);

不可以在指针上使用std::beginstd::end 与大小是类型的一部分的数组不同,因此指针不能保持它指向的东西的大小。 在您使用指针的情况下,您将不得不使用

std::find(pStart, pStart + SIZE, 5);

避免这种情况的方法是使用std::vector当你不知道szie在编译时会是什么时。 它将为您管理内存并提供beginend成员功能。

这里:

std::begin(pStart), std::end(pStart)

你试图抓住指针的开头和结尾。 不!

相反,你的意思是:

std::begin(vect), std::end(vect)

无论你使用数组, std::arraystd::vector ,还是特别大的大象,都可以获得容器的边界,你需要容器​​。

我想在C ++数组中使用迭代器,但也使用原始指针。

你倒退了。 原始指针迭代器。 他们迭代数组。

您可以将它们用于std::beginstd::end所能完成的所有事情。 最值得注意的是,您可以将它们传递给<algorithm> C ++标准算法。

指针本身不能被迭代。 迭代器不能迭代。

 int* pStart = vect; std::find(std::begin(pStart), std::end(pStart), 5); 

非常宽松地说,指针只是一个数字。 数字的“开始”和“结束”是什么? 这段代码与以下内容一样没有意义:

int i = 123;
std::find(std::begin(i), std::end(i), 5); // error

有可能让begin()end()意识到它吗?

指针可以指向某个数组的开头。 但是这些知识必须与指针一起保存。 您需要维护一个大小或结束指针以及一个开始指针,并将所有数据保存在一起。

这正是std::arraystd::vector为你做的事情。

当我处理阵列时,我依靠简单的容器来使它们与C ++对范围的一般处理兼容。

例如:

#include <iostream>
#include <memory>    // for std::unique_ptr
#include <algorithm> // for std::reverse
#include <numeric>   // for std::iota

template<typename T>

class range_view {

 public:

  range_view(T* data, std::size_t size)
      : m_data { data },
        m_size { size } { }

  const T* begin() const { return m_data; }
  const T* end() const { return m_data + m_size; }

  T* begin() { return m_data; }
  T* end() { return m_data + m_size; }

 private:

  T* m_data;
  std::size_t m_size;
};

int main() {

  // this is your actual data
  auto pdata = std::make_unique<int>(20);

  // this is a handle you use to work with your data
  auto data_view = range_view<int>(pdata.get(), 20);

  // for example, you can fill it with numbers 0, ... , N - 1
  std::iota(data_view.begin(), data_view.end(), 0);

  // it is now compatible with c++'s range-based operators
  std::cout << "my data...\n";
  for(auto && item : data_view) std::cout << item << " ";

  std::reverse(data_view.begin(), data_view.end());
  std::cout << "\nreversed...\n";
  for(auto && item : data_view) std::cout << item << " ";
  std::cout << "\n";
}

编译并运行

$ g++ example.cpp -std=c++14
$ ./a.out
my data...
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 
reversed...
19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 

您仍然需要担心将正确的维度传递给构造函数,如果删除了基础指针,它将会失败,但无论如何您都不得不担心。

虽然其他答案已经解释了为什么你应该重新审视你的设计,但我想说明一个选项,之前没有描述过。

您的编译器诊断消息几乎清楚地表明编译器会推断参数,并且该参数看起来与对 С 样式数组的引用完全一样。

对 C 样式数组的引用不会衰减为指针,因此您可以在特定情况下将 C 样式数组的引用作为选项传递给 std::begin 和 std::end:

#include <iostream>
#include <algorithm>

constexpr size_t SIZE = 10;

int main() {
    int vect[SIZE] = {0};
    vect[3] = 5;

    int (&ref_to_vect)[SIZE] = vect;    // declaring reference to C-array

        // and using reference to C-array which doesn't decay to pointer opposite to passing array "by value" semantics
    int* p = std::find(std::begin(ref_to_vect), std::end(ref_to_vect), 5);
    bool success = p != std::end(vect);
    std::cout << (success ? "Found 5" : "5 not found :(");

    return 0;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM