使用C ++的多维数组(矩阵)更有效的方法

时间:2014-01-01 22:04:22

标签: c++ matrix multidimensional-array

我编写了一个简单的小程序,比较几种方法的性能,用不同类型的容器填充简单的8x8矩阵。这是以下代码:

#define MATRIX_DIM 8
#define OCCUR_MAX 100000

static void genHeapAllocatedMatrix(void)
{
    int **pPixels = new Pixel *[MATRIX_DIM];

    for (type::uint32 idy = 0; idy < MATRIX_DIM; idy++) {
        pPixels[idy] = new Pixel[MATRIX_DIM];
        for (type::uint32 idx = 0; idx < MATRIX_DIM; idx++)
            pPixels[idy][idx] = 42;
    }
}

static void genStackAllocatedMatrix(void)
{
    std::array<std::array<int, 8>, 8> matrix;

    for (type::uint32 idy = 0; idy < MATRIX_DIM; idy++) {
        for (type::uint32 idx = 0; idx < MATRIX_DIM; idx++) {
            matrix[idy][idx] = 42;
        }
    }
}

static void genStackAllocatedMatrixBasic(void)
{
    int matrix[MATRIX_DIM][MATRIX_DIM];

    for (type::uint32 idy = 0; idy < MATRIX_DIM; idy++) {
        for (type::uint32 idx = 0; idx < MATRIX_DIM; idx++) {
            matrix[idy][idx] = 42;
        }
    }
}

int main(void)
{
    clock_t begin, end;
    double time_spent;

    begin = clock();

    for (type::uint32 idx = 0; idx < OCCUR_MAX; idx++)
    {
        //genHeapAllocatedMatrix();
        genStackAllocatedMatrix();
        //genStackAllocatedMatrixBasic();
    }

    end = clock();

    time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
    std::cout << "Elapsed time = " << time_spent << std::endl;

    return (0);
}

正如你猜测的那样,最有效的方法是使用简单的二维C数组(硬编码)。当然,更糟糕的选择是使用堆分配的第一名。 我的问题是我想将这个二维数组作为一个类中的属性存储。以下是处理矩阵的自定义类的定义:

template <typename T>
class Matrix
{
    public:
        Matrix(void);
        Matrix(type::uint32 column, type::uint32 row);
        Matrix(Matrix const &other);
        virtual ~Matrix(void);

    public:
        Matrix &operator=(Matrix const &other);
        bool operator!=(Matrix const &other);
        bool operator==(Matrix const &other);
        type::uint32 rowCount(void) const;
        type::uint32 columnCount(void) const;
        void printData(void) const;
        T **getData(void) const;
        void setData(T **matrix);

    private:
        type::uint32 m_ColumnCount;
        type::uint32 m_RowCount;
        T **m_pMatrix;
};

为了完成工作,我尝试使用强制转换:

Matrix<int> matrix;
int tab[MATRIX_DIM][MATRIX_DIM];

for (type::uint32 idy = 0; idy < MATRIX_DIM; idy++) {
    for (type::uint32 idx = 0; idx < MATRIX_DIM; idx++) {
        tab[idy][idx] = 42;
    }
}
matrix.setData((int**)&tab[0][0]);

此代码编译正确,但如果我想打印它则存在分段错误。

int tab[MATRIX_DIM][MATRIX_DIM];

for (type::uint32 idy = 0; idy < MATRIX_DIM; idy++) {
    for (type::uint32 idx = 0; idx < MATRIX_DIM; idx++) {
        tab[idy][idx] = 42;
    }
}
int **matrix = (int**)&tab[0][0];

std::cout << matrix[0][0] << std::endl; //Segmentation fault

有没有办法将这种二维数组存储为没有堆分配的属性?

3 个答案:

答案 0 :(得分:2)

那是因为二维数组不是指针数组。

因此,您应该将int *用于matrix类型,但当然您将无法通过两个维度对其进行索引。

另一种选择是存储指向数组的指针:

int (*matrix)[MATRIX_DIM][MATRIX_DIM];

matrix = &tab;
std::cout << (*matrix)[0][0] << std::endl;

但这并不适合在课堂上填充矩阵的想法。更好的想法是让类分配存储本身(可能在单个堆分配中)并仅通过方法(例如GetCell(row, col)等)提供对矩阵的访问,而不暴露原始指针。

答案 1 :(得分:1)

测量8 x 8阵列的操作速度基本上没有意义。对于小到这样的数据集,操作成本将接近于零,并且您主要测量设置时间等。

对于较大的数据集,计时变得很重要,但是您无法将小集合结果明确地推断到更大的数据集。对于较大的数据集,您通常会发现数据存在于多个内存页面上。寻呼成本将主导其他成本。通过确保算法在移动到下一页之前处理一页上的所有(或大部分)数据,而不是不断地交换页面,可以实现效率的极大提升。

通常,您最好使用最简单的数据结构,编程错误的可能性最小,并优化处理算法。我说“一般”,因为极端情况确实存在,访问时间的微小差异很重要,但它们很少见。

答案 2 :(得分:0)

使用单个数组表示矩阵,而不是为每个索引分配。

我已经为此写了一堂课。随意使用它:

#include <vector>

template<typename T, typename Allocator = std::allocator<T>>
class DimArray
{
    private:
        int Width, Height;
        std::vector<T, Allocator> Data;

    public:
        DimArray(int Width, int Height);
        DimArray(T* Data, int Width, int Height);
        DimArray(T** Data, int Width, int Height);
        virtual ~DimArray() {}

        DimArray(const DimArray &da);
        DimArray(DimArray &&da);

        inline std::size_t size() {return Data.size();}
        inline std::size_t size() const {return Data.size();}

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

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

        inline T* operator [](const int Index) {return Data.data() + Height * Index;}
        inline const T* operator [](const int Index) const {return Data.data() + Height * Index;}

        inline DimArray& operator = (DimArray da);
};

template<typename T, typename Allocator>
DimArray<T, Allocator>::DimArray(int Width, int Height) : Width(Width), Height(Height), Data(Width * Height, 0) {}

template<typename T, typename Allocator>
DimArray<T, Allocator>::DimArray(T* Data, int Width, int Height) : Width(Width), Height(Height), Data(Width * Height, 0) {std::copy(&Data[0], &Data[0] + Width * Height, const_cast<T*>(this->Data.data()));}

template<typename T, typename Allocator>
DimArray<T, Allocator>::DimArray(T** Data, int Width, int Height) : Width(Width), Height(Height), Data(Width * Height, 0) {std::copy(Data[0], Data[0] + Width * Height, const_cast<T*>(this->Data.data()));}

template<typename T, typename Allocator>
DimArray<T, Allocator>::DimArray(const DimArray &da) : Width(da.Width), Height(da.Height), Data(da.Data) {}

template<typename T, typename Allocator>
DimArray<T, Allocator>::DimArray(DimArray &&da) : Width(std::move(da.Width)), Height(std::move(da.Height)), Data(std::move(da.Data)) {}

template<typename T, typename Allocator>
DimArray<T, Allocator>& DimArray<T, Allocator>::operator = (DimArray<T, Allocator> da)
{
    this->Width = da.Width;
    this->Height = da.Height;
    this->Data.swap(da.Data);
    return *this;
}

<强>用法:

int main()
{
    DimArray<int> Matrix(1000, 1000); //creates a 1000 * 1000 matrix.
    Matrix[0][0] = 100;  //ability to index it like a multi-dimensional array.
}

更多用法:

template<typename T, std::size_t size>
class uninitialised_stack_allocator : public std::allocator<T>
{
    private:
        alignas(16) T data[size];

    public:
        typedef typename std::allocator<T>::pointer pointer;
        typedef typename std::allocator<T>::size_type size_type;
        typedef typename std::allocator<T>::value_type value_type;

        template<typename U>
        struct rebind {typedef uninitialised_stack_allocator<U, size> other;};

        pointer allocate(size_type n, const void* hint = 0) {return static_cast<pointer>(&data[0]);}
        void deallocate(void* ptr, size_type n) {}
        size_type max_size() const {return size;}
};

int main()
{
    DimArray<int, uninitialised_stack_allocator<int, 1000 * 1000>> Matrix(1000, 1000);
}