C++ 为什么在创建矩阵类时使用向量不好?

C++ 为什么在创建矩阵类时使用向量不好?,c++,c++11,C++,C++11,对于我的矩阵课程,我做了: template<typename T, std::uint32_t Height, std::uint32_t Width> class Matrix { private: std::array<std::array<T, Width>, Height> Elements; static_assert(std::is_arithmetic<T>::value, "Argument

对于我的矩阵课程,我做了:

template<typename T, std::uint32_t Height, std::uint32_t Width>
class Matrix
{
    private:
        std::array<std::array<T, Width>, Height> Elements;
        static_assert(std::is_arithmetic<T>::value, "Argument T must be of arithmetic type.");

    public:
        Matrix();
        Matrix(T* Data);
        Matrix(T** Data);
        Matrix(T Data[Height][Width]);
        Matrix(const std::array<std::array<T, Width>, Height> &Data);

        inline int size() {return Width * Height;}
        inline const int size() const {return Width * Height;}

        inline int width() {return Width;}
        inline const int width() const {return Width;}

        inline int height() {return Height;}
        inline const int height() const {return Height;}

        std::array<T, Width>& operator[](int Index);
        const std::array<T, Width>& operator[](int Index) const;

        Matrix& operator = (const Matrix &M);

        Matrix& operator + (const Matrix &M);

        Matrix& operator - (const Matrix &M);

        Matrix& operator * (const Matrix &M);
};

template<typename T, std::uint32_t Height, std::uint32_t Width>
Matrix<T, Height, Width>::Matrix() {std::memset(&Elements, 0, sizeof(T) * Width * Height);}

template<typename T, std::uint32_t Height, std::uint32_t Width>
Matrix<T, Height, Width>::Matrix(T* Data) {if (Data) std::memcpy(&Elements, Data, sizeof(T) * Width * Height);}

template<typename T, std::uint32_t Height, std::uint32_t Width>
Matrix<T, Height, Width>::Matrix(T** Data) {if (Data) std::memcpy(&Elements, &Data[0][0], sizeof(T) * Width * Height);}

template<typename T, std::uint32_t Height, std::uint32_t Width>
Matrix<T, Height, Width>::Matrix(T Data[Height][Width]) {std::memcpy(&Elements, &Data[0][0], sizeof(T) * Width * Height);}

template<typename T, std::uint32_t Height, std::uint32_t Width>
Matrix<T, Height, Width>::Matrix(const std::array<std::array<T, Width>, Height> &Data) {std::memcpy(&Elements, &Data[0][0], sizeof(T) * Width * Height);}

template<typename T, std::uint32_t Height, std::uint32_t Width>
std::array<T, Width>& Matrix<T, Height, Width>::operator[](int Index) {return Elements[Index];}

template<typename T, std::uint32_t Height, std::uint32_t Width>
const std::array<T, Width>& Matrix<T, Height, Width>::operator[](int Index) const {return Elements[Index];}
模板
类矩阵
{
私人:
std::数组元素;
静态_断言(std::is_算术::value,“参数T必须是算术类型”);
公众:
矩阵();
矩阵(T*数据);
矩阵(T**数据);
矩阵(T数据[高度][宽度]);
矩阵(常数std::数组和数据);
内联int size(){返回宽度*高度;}
内联常量int size()常量{返回宽度*高度;}
内联int-width(){return width;}
内联常量int width()常量{返回宽度;}
内联int height(){return height;}
内联常量int height()常量{返回高度;}
std::数组和运算符[](int索引);
常量std::数组和运算符[](int索引)常量;
矩阵和运算符=(常数矩阵和M);
矩阵和运算符+(常数矩阵和M);
矩阵与算子-(常数矩阵与M);
矩阵与算子*(常数矩阵与M);
};
模板
矩阵::矩阵(){std::memset(&Elements,0,sizeof(T)*宽度*高度);}
模板
矩阵::矩阵(T*Data){if(Data)std::memcpy(&Elements,Data,sizeof(T)*宽度*高度);}
模板
矩阵::矩阵(T**Data){if(Data)std::memcpy(&Elements,&Data[0][0],sizeof(T)*宽度*高度);}
模板
矩阵::矩阵(T数据[高度][宽度]{std::memcpy(&Elements,&Data[0][0],sizeof(T)*宽度*高度);}
模板
矩阵::矩阵(常数std::数组和数据){std::memcpy(&元素,&数据[0][0],sizeof(T)*宽度*高度);}
模板
std::array&Matrix::operator[](int-Index){返回元素[Index];}
模板
常量std::数组和矩阵::运算符[](int索引)常量{返回元素[Index];}
因为我在网上读到很多评论,说不要使用向量,而是使用数组或std::valarray

现在我问这个问题的原因是因为我想重新编写我的matrix类,这样我就不必每次都做:
matrix
。。我宁愿在构造函数中这样做一次,而不必为每个函数都键入。。如上所述。例如,我必须为每个函数和每个矩阵参数编写长模板声明。此外,我不确定如何删除向量的调整大小/回推,这样当用户索引向量时,他们将无法调整它的大小,所以我使用了数组

我本来打算使用一个1D数组,并对它进行索引(I*Width+J),但后来我失去了[][]操作符


使用向量中的向量不好吗?有什么办法可以改进我的课堂并使之保持一致吗?我不太明白如何使用valarray,上面的内容很难维护。任何想法都值得赞赏。

诚然,向量向量并不是最好的方法。假设数据是矩形的(不是锯齿状的),向量向量方法的分配效率较低,更不用说它阻止了某种常见的“重塑”操作(“将我的2x3矩阵视为3x2或6x1而不复制”)

我本来打算使用一个1D数组,并对它进行索引(I*Width+J),但后来我失去了[][]操作符

当然,使用一维向量。太好了。然后,您可以调整它的大小、重塑它的形状等,并为许多操作提供接近最佳的性能。你留着雷伊


但是您不想失去双下标(
[x][y]
)的功能吗?好啊只需让您的
操作符[]
返回一个代理对象(由您实现)。代理将有自己的
操作符[]
,它将在第二个轴上运行。也就是说,第一个
[]
将返回一个轻量级对象,该对象只知道实现第二个
[]

对于密集矩阵类的备份存储,使用
向量
非常好,但是使用一个
向量
而不是简单的
向量
。还可以将宽度、高度和行/列主排序作为矩阵类的运行时属性

向量的问题在于它将使用N个动态分配,其中N是行数或列数。将矩阵存储在一维主订单块中更有效,因为它使用1个动态分配

另外,通过将行/列主排序设置为运行时属性,转置操作的时间是常数


对于类上的实际矩阵运算,有一个名为BLAS的标准接口,您可以传递操作数和结果实例的备份存储。对于每个使用特定CPU的非常低级别的性能的平台来说,都有高度优化的BLA实现,而且比标准C++中的表达速度要快得多。

< P>如果使用一维数组,仍然可以实现[]]],放弃一点安全性。p> 假设您的内部数据是T*(最基本的形式)。您可以返回指向行的第一个元素的指针:

template<typename T>
class Matrix
{
    private:
        int height_, width_;
        T* data_;
    public:
        Matrix(int height, int width):
                height_(height),
                width_(width) {
            data_ = new T[height * width];
            std::fill(data_, data_ + height * width, T());
        }
        T* operator[](const int &row) { // i'm returning a pointer to the start of the row
            return data_ + width_ * row;
        }

        const T* operator[](const int &row) const {
            return data_ + width_ * row;
        }
};

int main() {
    Matrix<int> M(5, 5);

    M[3][3] = 1;
    M[3][5] = 2; // this is bad but will work and actually fill the next cell

    std::cout << M[4][0] << std::endl;
}
模板
类矩阵
{
私人:
整数高度,宽度;
T*数据;
公众:
矩阵(整数高度、整数宽度):
高度(高度),,
宽度(宽度){
数据=新T[高度*宽度];
填充(数据+高度*宽度,T());
}
T*运算符[](const int&row){//我返回一个指向行开头的指针
返回数据+宽度*行;
}
常量T*运算符[](常量int和row)常量{
返回数据+宽度*行;
}
};
int main(){
矩阵M(5,5);
M[3][3]=1;
M[3][5]=2;//这不好,但会起作用并实际填充下一个单元格

std::cout你从哪里读到的?这是错误的。另外,提供
[]][]
,而你的数组构造函数并没有做你认为它在做的事情(它不是数组,签名等同于
**
一个,你正在重新定义该构造函数)最后,使用typesafe
std::copy
和not
std::memcpy
。它已经是行主顺序,所以[