[英]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.