簡體   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