[英]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::begin
和std::end
。 與大小是類型的一部分的數組不同,因此指針不能保持它指向的東西的大小。 在您使用指針的情況下,您將不得不使用
std::find(pStart, pStart + SIZE, 5);
避免這種情況的方法是使用std::vector
當你不知道szie在編譯時會是什么時。 它將為您管理內存並提供begin
和end
成員功能。
這里:
std::begin(pStart), std::end(pStart)
你試圖抓住指針的開頭和結尾。 不!
相反,你的意思是:
std::begin(vect), std::end(vect)
無論你使用數組, std::array
, std::vector
,還是特別大的大象,都可以獲得容器的邊界,你需要容器。
我想在C ++數組中使用迭代器,但也使用原始指針。
你倒退了。 原始指針是迭代器。 他們迭代數組。
您可以將它們用於std::begin
和std::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::array
和std::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.