c++中的矢量存储
Vector storage in C++
我希望存储一个大的d维点向量(d固定且小:<10)。
如果我将Point
定义为vector<int>
,我认为vector<Point>
将在每个位置存储一个指向点的指针。
但是如果将Point
定义为固定大小的对象,如下所示:std::tuple<int,int,...,int>
或std::array<int, d>
,程序是否将所有点存储在连续内存中,还是保留额外的间接层?
如果答案是数组避免了额外的间接,那么在扫描vector<Point>
时,这会对性能(缓存利用局部性)产生很大的影响吗?
如果您将Point
定义为具有连续数据存储(例如struct Point { int a; int b; int c; }
或使用std::array
),那么std::vector<Point>
将在连续内存位置存储Point
s,因此您的内存布局将为:
p0.a, p0.b, p0.c, p1.a, p1.b, p1.c, ..., p(N-1).a, p(N-1).b, p(N-1).c
另一方面,如果将Point
定义为vector<int>
,则vector<Point>
具有vector<vector<int>>
的布局,即不是连续的,因为vector
将指针存储到动态分配的内存中。所以你有单个 Point
s的连续性,但不是整个结构。
第一个解决方案比第二个更有效(因为现代cpu喜欢访问连续的内存位置)。
vector
将在连续内存中存储您的类型包含的任何内容。所以,是的,如果那是array
或tuple
,或者更好的是,自定义类型,它将避免间接。
性能方面,一如既往,你必须衡量它。不要投机。至少就扫描而言。
然而,当您首先创建这些点时,肯定会有巨大的性能增益,因为您将避免为每个存储点的vector
分配不必要的内存。在c++中,内存分配通常非常昂贵。
对于上述d
(<10)的值,将Point
定义为vector<int>
几乎会使std::vector<Point>
的全部内存使用量增加一倍,并且几乎不会带来任何优势。
由于维度是固定的,我建议您使用使用维度作为模板参数的模板。像这样:
template <typename R, std::size_t N> class ndpoint
{
public:
using elem_t=
typename std::enable_if<std::is_arithmetic<R>::value, R>::type;
static constexpr std::size_t DIM=N;
ndpoint() = default;
// e.g. for copying from a tuple
template <typename... coordt> ndpoint(coordt... x) : elems_ {static_cast<R>(x)...} {
}
ndpoint(const ndpoint& other) : elems_() {
*this=other;
}
template <typename PointType> ndpoint(const PointType& other) : elems_() {
*this = other;
}
ndpoint& operator=(const ndpoint& other) {
for(size_t i=0; i<N; i++) {
this->elems_[i]=other.elems_[i];
}
return *this;
}
// this will allow you to assign from any source which defines the
// [](size_t i) operator
template <typename PointT> ndpoint& operator=(const PointT& other) {
for(size_t i=0; i<N; i++) {
this->elems_[i]=static_cast<R>(other[i]);
}
}
const R& operator[](std::size_t i) const { return this->elems_[i]; }
R& operator[](std::size_t i) { return this->elems_[i]; }
private:
R elems_[N];
};
然后使用std::vector<ndpoint<...>>
作为最佳性能点的集合。
100%确定数据结构的唯一方法是完全实现自己的内存处理。
但是,有许多库实现了矩阵和矩阵操作,您可以查看这些库。有些已经记录了关于连续内存,重塑等的信息(例如OpenCV Mat)。
注意,一般来说,你不能相信点的数组是连续的。这是由于对齐,分配块头等。例如考虑
struct Point {
char x,y,z;
};
Point array_of_points[3];
现在,如果你尝试"重塑",即根据点在容器中相邻的事实在点元素之间迭代,那么它很可能会失败:
(char *)(&array_of_points[0].z) != (char *)(&array_of_points[1].x)
- 将字符串存储在c++中的稳定内存中
- std::原子加载和存储都需要吗
- C++:将控制台输出存储在宏中更好吗
- 使用QProcess执行命令,并将结果存储在QStringList中
- 访问存储在向量C++中的结构的多态成员
- 如何从存储在std::映射中的std::集中删除元素
- 存储模板类型以强制转换回派生<T>
- 类型总是使用其大小存储在内存中吗
- 当字符串存储在变量中时,如何将字符串转换为wchar_t
- 使用无符号字符数组有效存储内存
- 如何在cpp.中使用协议缓冲区存储大缓冲区/数组(char/int)
- 使用 pqxx 将 std::vector 存储在 postgresql 中,并从数据库中检索它
- 带结构的二维矢量:如何存储元素
- 添加存储在向量中的大整数的函数出现问题
- 从文件中读取多个字节,并将它们存储在C++中进行比较
- 在std::vector上存储带有模板的类实例
- 谷歌测试中的期望值存储在哪里
- 为什么C中的通用链表中存储的数据已损坏
- 在c++中获取两个大int,并将它们存储在数组中
- 在reactor中存储eventHandlers的最佳方式是什么