正如标题中所述,我找到了大量解决方案。大多数人会说std::array<4, std::array<4, int>>
或std::vector<std::vector<int>>
是好的,但是我发现这看起来很混乱,很难扩展到多维数组。另外,我担心这些数组实际上是对象数组,可能会带来一些开销(我想是这样,不是很确定)。那么最好的方法是什么?
答案 0 :(得分:3)
一些要点让您入门。
首先,std::array
对std::vector
。这很容易。如果您在编译时知道2d数组的大小,则可以肯定std::array
否则std::vector
。
std::vector<std::vector<T>>
可以满足需要快速准备的事情,并且很少在对性能不重要的代码中很少使用(1)。
std::vector<std::vector<T>>
的最大缺点是内存布局。您有两次间接访问,并且每行都是单独分配的,这对缓存造成了严重破坏,因此在性能关键代码(1)中绝对是不行的。对于性能至关重要的代码,您需要使用成熟的数学库。专家可以比您或我更好地编写面向性能的代码,并且这种库的另一个重要优点是它通过了时间的考验。
如果出于任何原因要自己编写此代码,则解决方案是将矩阵展平。即使用std::vector<T>(numRows * numColumns)
,然后使用以下公式访问元素:(i, j) -> v[i * numColumns + j]
。并将其包装在一个不错的界面中。界面的复杂程度以及您允许对其进行哪种操作完全取决于您。
(1)我想指出,大多数情况下,尤其是新手程序员完全误解了性能问题(由于缺乏经验,这是完全可以理解的)。首先,有一些普遍适用的实践适用于任何情况。然后是对算法和所用数据类型的分析。但是除此之外,您首先编写代码以提高可读性,然后,如果考虑到性能,则对代码进行概要分析,并开始优化概要分析器告诉您的位置。
答案 1 :(得分:2)
我碰巧有这个未经测试的示例。如果可行,那么很好,否则它是如何在2D
数组上创建1D
视图的一个示例:
template<typename T>
class two_dee_array
{
public:
two_dee_array(std::size_t row, std::size_t col)
: v(row * col), stride(col) {}
T& operator()(std::size_t row, std::size_t col)
{ return v[(row * stride) + col]; }
T const& operator()(std::size_t row, std::size_t col) const
{ return v[(row * stride) + col]; }
std::size_t col_size() const { return stride; }
std::size_t row_size() const { return v.size() / stride; }
auto begin() { return std::begin(v); }
auto end() { return std::end(v); }
auto begin() const { return std::begin(v); }
auto end() const { return std::end(v); }
auto cbegin() const { return std::cbegin(v); }
auto cend() const { return std::cend(v); }
private:
std::vector<T> v;
std::size_t stride;
};
答案 2 :(得分:0)
使用多维数组时,首先想到的是Matrix
。我将显示Matrix
的{{1}} classes
的3个变体。在前两种情况下,您将看到数据存储在一维数组中,但是基于2D转换进行索引。在第三种类型中,我仅使用一个templates
来保存所有内容,但是我使用另一个std::vector<Type>
来保存所有用于索引到高维矩阵的每个维度的步幅。
第1个 st 是std::vector<size_t>
:-这将执行任何MxM - Matrix
Square Matrix
第2 nd 是template<class T, unsigned M>
class Matrix {
static const unsigned Stride = M;
static const Size = Stride * Stride;
T data[Size] = {};
public:
Matrix() {};
Matrix( const T* dataIn ) {
fillMatrix( dataIn );
}
void fillMatrix( const T* dataIn );
void printMatrix();
};
template<class T, unsigned M>
void Matrix<T,M>::fillMatrix( const T* dataIn ) {
for ( unsigned int i = 0; i < Size; i++ ) {
this->data[i] = dataIn[i];
}
}
template<class T, unsigned M>
void Matrix<T,M>::printMatrix() {
for ( unsigned int i = 0; i < Stride; i++ ) {
for ( unsigned int j = 0; j < Stride; j++ ) {
std::cout << this->data[i*Stride + j] << " ";
}
std::cout << '\n';
}
}
:-这将执行任何2D矩阵
MxN - Matrix
第3个 rd 是template<class T, unsigned M, unsigned N>
class Matrix {
private:
static const unsigned Row = M;
static const unsigned Col = N;
static const unsigned Size = M * N;
T data[Size] = {};
public:
Matrix() {};
Matrix( const T* dataIn ) {
fillMatrix( dataIn );
}
void fillMatrix( const T* dataIn );
void printMatrix();
};
template<class T, unsigned M, unsigned N>
void Matrix<T,M,N>::fillMatrix( const T* dataIn ) {
for( unsigned int i = 0; i < Size; i++ ) {
this->data[i] = dataIn[i];
}
}
template<class T, unsigned M, unsigned N>
void Matrix<T,M,N>::printMatrix() {
for( unsigned int i = 0; i < Row; i++ ) {
for( unsigned int j = 0; j < Col; j++ ) {
std::cout << this->data[i*Col + j] << " ";
}
std::cout << '\n';
}
}
:它将执行任何MxNx... - Matrix
。
注意-这需要具有支持可变参数模板的编译器的现代C ++!看起来像这样。前两个将编译,您可以按原样使用。至于
这个;我没有展示整个课程,因为这只是冰山一角。我喜欢称其为体积矩阵的功能非常强大,并且有太多源可在此处发布,并且我的某些功能尚未完成。它还依赖于其他几个帮助程序类模板,并使用各种其他类型的类模板,这些类模板均与矩阵特别相关,以进行存储,记录等。但是它的基本外壳看起来像这样:
Arbitrary Matrix
它几乎完成的头文件看起来像这样,因为它仍在进行中,并且仅说明矩阵的实际存储情况:我仍然需要处理它的任何template<typename Type, size_t... Dims>
class Matrix {
public:
static const size_t numDims_ = sizeof...(Dims);
private:
size_t numElements_;
std::vector<Type> elements_;
std::vector<size_t> strides_;
public:
Matrix() noexcept;
template<typename... Arg>
Matrix( Arg&&... as ) noexcept;
const Type& operator[]( size_t idx ) const;
size_t numElements() const {
return elements_.size();
}
const std::vector<size_t>& strides() const {
return strides_;
}
const std::vector<Type>& elements() const {
return elements_;
}
}; // Matrix
方面。
calculation