我想用一个自定义容器遍历一个预先分配的浮点数组,该容器不拥有数据,但作用于其中的一段。例如,将容器类命名为LinhaSobre
:
std::unique_ptr<float[]> data(new float[720]);
...
//creates container to iterate 26 floats starting from from data[12]
LinhaSobre cont(data.get()+12, 26);
//sets those elements to 1.5
for(size_t i = 0; i < cont.size(); i++)
cont[i] = 1.5f;
以下是operator[]
:的可能实现
//...
//LinhaSobre has a member mem0 which is initialized
//as a pointer to where the interval starts
float & LinhaSobre::operator[] (size_t i)
{
return *(mem0+i);
}
请注意,我将从LinhaSobre::operator[]
返回一个对它不拥有的数据的引用。它不应该干扰数据的生存期(构造函数、析构函数)。
现在,我想通过另一种模式std::array<float,4>
公开存储的data
,而不是纯的float
。示例,命名新类LinhaSobre4f
:
std::unique_ptr<float[]> data(new float[720]);
...
//creates container to iterate 4 array<float, 4> starting from from data[12]
LinhaSobre4f l(data.get()+(3*4), 4);
//sets those elements to {1.5f, 2.5f, 3.5f, 4.5f};
for(size_t i = 0; i < l.size(); i++)
l[i] = { {1.5f, 2.5f, 3.5f, 4.5f} };
请注意,我将这些项视为一个数组。这将导致容器类的一些更改,我主要关心的是operator[]
,下面是完整的类代码:
struct LinhaSobre4f
{
LinhaSobre4f(float * pos_begin, size_t size_):
pos0(pos_begin),
size_(size_){}
std::array<float, 4> & operator[](size_t i)const
{
std::array<float,4> * r =
reinterpret_cast<std::array<float,4>*> (pos0+(4*i));
return *r;
}
size_t size()const
{
return size_;
}
private:
float * pos0;
size_t size_;
};
operator[]
返回对被视为std::array<float,4>
的内存块的引用,该内存块从未真正存在过,但在std::array
内存布局保证的情况下,它可以工作。我对此持怀疑态度,可以吗?(除了内存对齐,我保证)。我可以从语义上公开这样的对象吗?正确的术语是什么?(我在标题中使用了假对象)。
下面是该示例的现场演示。这是另一个(另一个链接有时会失败)
C++标准(我正在阅读C++11)定义std::array
如下:
应满足骨料的条件(8.5.1)。
不能保证std::array
是POD。C++标准只保证它是一个类聚合。
基于此,我认为您使用reinterpret_cast
将float
s的POD数组转换为std::array
是未定义的行为。
它很可能与编译器一起工作,但不能保证它是可移植的或合法的。
您可以创建一个普通的旧reference_type:
struct LinhaSobre4f {
struct Ref {
Ref(float *m): m(m){};
Ref &operator=(std::initializer_list<float> const &l) {
std::copy(l.begin(), l.end(), m);
return *this;
}
private:
float *m;
};
Ref operator[](size_t i) { return m + 4 * i; }
private:
float *m;
};
再加上Sam Varshavchik的回答,您可能会对span
类型(以前称为array_view
)感兴趣。
span
类型是一种抽象,它提供了对连续对象序列的视图,对象序列的存储由其他对象所有(更多详细信息,请参阅P0122R1,CppCoreGuidelines和Guidelines Support Library Review:span<T>
)。
从概念上讲,span
只是指向某个存储的指针和可通过该指针访问的元素的计数。它太小了,可以通过值传递。
开放源代码(仅限标头)的引用实现可在https://github.com/Microsoft/GSL(该实现通常假设一个实现C++14支持的平台。有特定的解决方案来支持MSVC 2013和2015)。