将 std::vector 用于动态分配的二维数组?
use std::vector for dynamically allocated 2d array?
所以我正在写一个 class,它有 1d 数组和 2d 数组,我在构造函数中动态分配
class Foo{
int** 2darray;
int * 1darray;
};
Foo::Foo(num1, num2){
2darray = new int*[num1];
for(int i = 0; i < num1; i++)
{
array[i] = new int[num2];
}
1darray = new int[num1];
}
然后我将不得不在析构函数中删除每个一维数组和二维数组中的每个数组,对吗?
我想使用 std::vector 不必这样做。这样做有什么缺点吗? (使编译变慢等?)
TL;DR: 何时对动态分配的数组使用 std::vector,在运行时不需要调整大小?
应该没有任何缺点,因为 vector guarantees contiguous memory. But if the size is fixed and C++11 is available maybe an array 在其他选项中:
- 它不允许调整大小
- 根据
vector
的初始化方式防止重新分配
- 大小在指令中被硬编码(模板参数)。有关更详细的描述,请参阅 Ped7g 评论
vector
适用于绝大多数用途。手动调优方案应首先尝试调优分配器1,然后才修改容器。内存管理(以及您的程序)的正确性比任何编译时间收益都重要得多。
换句话说,vector
应该是你的出发点,直到你觉得不尽如人意,你不应该关心其他任何事情。
作为额外的改进,考虑使用一维 vector
作为后端存储并且只提供二维索引视图。这种方案可以提高缓存局部性和整体性能,同时也使一些操作(如复制整个结构)变得更加容易。
1 vector
接受的两个模板参数中的第二个,默认为给定类型的标准分配器。
二维数组不是指针数组。
如果你这样定义它,每个 row/colum 可以有不同的大小。
此外,元素在内存中不会按顺序排列。
这可能会导致性能不佳,因为预取器无法很好地预测您的访问模式。
因此,不建议将 std::vectors 嵌套在彼此内部以对多维数组进行建模。
更好的方法是通过提供自定义访问方法将连续的内存块映射到多维space。
您可以在浏览器中测试:http://fiddle.jyt.io/github/3389bf64cc6bd7c2218c1c96f62fa203
#include<vector>
template<class T>
struct Matrix {
Matrix(std::size_t n=1, std::size_t m=1)
: n{n}, m{m}, data(n*m)
{}
Matrix(std::size_t n, std::size_t m, std::vector<T> const& data)
: n{n}, m{m}, data{data}
{}
//Matrix M(2,2, {1,1,1,1});
T const& operator()(size_t i, size_t j) const {
return data[i*m + j];
}
T& operator()(size_t i, size_t j) {
return data[i*m + j];
}
size_t n;
size_t m;
std::vector<T> data;
using ScalarType = T;
};
您可以通过返回一个可以访问数据、索引和维度的 VectorView 来实现 operator[]。
所以我正在写一个 class,它有 1d 数组和 2d 数组,我在构造函数中动态分配
class Foo{
int** 2darray;
int * 1darray;
};
Foo::Foo(num1, num2){
2darray = new int*[num1];
for(int i = 0; i < num1; i++)
{
array[i] = new int[num2];
}
1darray = new int[num1];
}
然后我将不得不在析构函数中删除每个一维数组和二维数组中的每个数组,对吗? 我想使用 std::vector 不必这样做。这样做有什么缺点吗? (使编译变慢等?)
TL;DR: 何时对动态分配的数组使用 std::vector,在运行时不需要调整大小?
应该没有任何缺点,因为 vector guarantees contiguous memory. But if the size is fixed and C++11 is available maybe an array 在其他选项中:
- 它不允许调整大小
- 根据
vector
的初始化方式防止重新分配 - 大小在指令中被硬编码(模板参数)。有关更详细的描述,请参阅 Ped7g 评论
vector
适用于绝大多数用途。手动调优方案应首先尝试调优分配器1,然后才修改容器。内存管理(以及您的程序)的正确性比任何编译时间收益都重要得多。
换句话说,vector
应该是你的出发点,直到你觉得不尽如人意,你不应该关心其他任何事情。
作为额外的改进,考虑使用一维 vector
作为后端存储并且只提供二维索引视图。这种方案可以提高缓存局部性和整体性能,同时也使一些操作(如复制整个结构)变得更加容易。
1 vector
接受的两个模板参数中的第二个,默认为给定类型的标准分配器。
二维数组不是指针数组。 如果你这样定义它,每个 row/colum 可以有不同的大小。 此外,元素在内存中不会按顺序排列。 这可能会导致性能不佳,因为预取器无法很好地预测您的访问模式。 因此,不建议将 std::vectors 嵌套在彼此内部以对多维数组进行建模。 更好的方法是通过提供自定义访问方法将连续的内存块映射到多维space。
您可以在浏览器中测试:http://fiddle.jyt.io/github/3389bf64cc6bd7c2218c1c96f62fa203
#include<vector>
template<class T>
struct Matrix {
Matrix(std::size_t n=1, std::size_t m=1)
: n{n}, m{m}, data(n*m)
{}
Matrix(std::size_t n, std::size_t m, std::vector<T> const& data)
: n{n}, m{m}, data{data}
{}
//Matrix M(2,2, {1,1,1,1});
T const& operator()(size_t i, size_t j) const {
return data[i*m + j];
}
T& operator()(size_t i, size_t j) {
return data[i*m + j];
}
size_t n;
size_t m;
std::vector<T> data;
using ScalarType = T;
};
您可以通过返回一个可以访问数据、索引和维度的 VectorView 来实现 operator[]。