2

我想将矩阵从一个函数传递到另一个函数,所以我做了:

#include <cstdlib>
using namespace std;

const int N = 2;

void init_matrix(int (*matrix)[N]) 
{
    for (int i = 0; i < N; ++i)
        for (int j = 0; j < N; ++j)
            matrix[i][j] = 1;
}

int main() 
{
    int *x = (int*)malloc(N*N*sizeof(int));
    init_matrix( (int (*)[N]) x );
    return 0;
}

如何让通话init_matrix()更轻松?我想象它像init_matrix(x, N)

请注意,我有点避免std::vector,因为我很快就会使用并行编程(pthreads、OpenMP、MPI)。所以我会要求一个没有std构建矩阵方法的解决方案。

4

5 回答 5

3

只是不要。

多维数组并不是 C++ 最好的地方。在这里它仍然是可以接受的,因为 N 是一个编译时间常数,但如果它是一个运行时变量,你会被关闭,因为标准 C++ 不支持 VLA(即使它们被一些实现支持作为实现扩展,如 gcc 和铛)。

因此,如果您真的需要处理真正的 2D 数组,只需使用一个自定义类,该类包含一个std::array用于固定编译时间维度的底层或一个用于运行时维度的向量以获得总大小,并为其提供 2d 访问器。由于std::arrays和向量是对象,因此您可以避免资源复制和移动噩梦(*)。

一个简化的实现可能是:

class matrix {
   std::vector<int> vec;
   int  rows;
   int cols;

public:
   matrix(int i, int j): rows(i), cols(j), vec(i * j) {}

   int& at(int i, int j) {
       return vec[j + i * cols];
   }

   const int& at(int i, int j) const {
       return vec[j + i * cols];
   }
};

这样,底层结构仍然是一个真正的二维数组,并且您确实有方法使用它的二维

这里还缺少什么:

  • 索引和大小可能应该size_t代替int
  • 可以在at方法中测试索引是否在可接受的范围内-如果您不检查它们,则不应调用该函数at...
  • 其他构造函数在现有二维数组之上构建矩阵(例如,可能来自 C 遗留代码)

补充说明:

你说你想避免可能的多线程的向量。首先,我无法想象为什么向量的多线程安全性不如手动分配的动态数组。其次,如果您确实需要手动分配,则必须遵循三/五规则,并在自定义析构函数之外实现自定义复制/移动构造函数和赋值运算符。


(*) 我有一个项目要编写一个通用的多维容器支持operator []和迭代器,所以我知道这是一项相当复杂的任务。我已经向代码审查提交了一个预版本,但它仍然远非简单可用。

于 2018-06-08T09:56:41.000 回答
3

您可以使用别名使调用看起来更好:

#include <cstdlib>
#include <iostream>
using namespace std;

const int N = 2;

using TypeMatrix =int (*)[N]; //alias

void init_matrix(TypeMatrix matrix) { //simply use the alias
    for (int i = 0; i < N; ++i)
        for (int j = 0; j < N; ++j)
            matrix[i][j] = 1;
}


int main() {
    TypeMatrix x = (TypeMatrix)(int*)malloc(N*N*sizeof(int)); //avoid malloc
    init_matrix(x);
   }

另请注意,您可以使用模板别名将其提升到一个新的水平,如下所示:

#include <cstdlib>
#include <iostream>
using namespace std;

const int N = 2;

template<typename T , int K>
using TypeMatrix =T (*)[K];

using MatrixInt =TypeMatrix<int,N>;
using MatrixDouble =TypeMatrix<double,N>;


template <typename Matrix>
void init_matrix(Matrix matrix) {
    for (int i = 0; i < N; ++i)
        for (int j = 0; j < N; ++j)
            matrix[i][j] = 1.1;
}


template <typename Matrix>
void print(Matrix matrix) {
    for (int i = 0; i < N; ++i)
        for (int j = 0; j < N; ++j)
            std::cout<<matrix[i][j]<< " ";
}


int main() {
    MatrixInt x = (MatrixInt) (new int[N*N]);
    MatrixDouble y = (MatrixDouble) (new double[N*N]);
    init_matrix(x);
    init_matrix(y);
    print(x);
    print(y);
}

也就是说,我非常不鼓励使用原始指针以及混合 C 和 C++ ( mallocvs new) 来完成这种工作。使用std::arraystd::vector代替。

于 2018-06-08T09:59:17.343 回答
0

使用std::vector多线程编程没有任何问题,例如解释here。任何其他存储都同样危险。

除了其他答案中显示的所有向量示例:如果您使用的是固定大小的矩阵,您甚至可以考虑使用基于std::array.

#include <iostream>
#include <array>

template <class T, size_t rows, size_t cols>
class Matrix {
public:
    Matrix() {}
    Matrix(T init) { data.fill(init); }
    double& operator() (size_t row, size_t col)
    {
        if (row < rows && col < cols) return data[cols*row + col];
        throw std::out_of_range("Matrix subscript out of bounds.");
    }
    double operator() (size_t row, size_t col) const
    {
        return data(row, col);
    }
private:
    std::array<T, rows*cols> data;
};

int main()
{
    Matrix<double, 2, 2> mat(1.0);
    mat(1,1) = 2.3;
    std::cout << "mat(1,1) = " << mat(1,1) << std::endl;
}

ps 示例中实现的无效大小检查。

于 2018-06-08T12:37:44.797 回答
0

If you need dynamic allocation of contiguous integers for some reason, you can use a vector of arrays, or a smart pointer.

std::vector<int[N]> x(N);
std::unique_ptr<int[][N]> x = std::make_unique<int[][N]>(N);

Using your implementation of init_matrix, you can simply pass in the address of the first element.

init_matrix(&x[0]);

However, it would be preferable to pass the vector or smart pointer in by reference.

void init_matrix (std::vector<int[N]> &matrix) {
    ...
}

void init_matrix (std::unique_ptr<int[][N]> &matrix) {
    ...
}

...
init_matrix(x);
于 2018-06-08T09:53:33.223 回答
0

malloc忽略在 C++中使用的不良做法,然后......

您可以将函数参数中的数组指针替换为数组。这将衰减回数组指针,但它使函数接口更加清晰。

您不能在 C 和 C++ 之间int(*)[N]进行(int*)转换。它们不是兼容的指针类型。即使它们指向同一个地址,您也会遇到由严格的指针别名引起的未定义行为问题。

可以像这样重写代码,但也不建议这样做:

#include <cstdlib>
using namespace std;

const int N = 2;

void init_matrix(int matrix[N][N]) {
    for (int i = 0; i < N; ++i)
        for (int j = 0; j < N; ++j)
            matrix[i][j] = 1;
}

int main() {
    int (*x)[N] = (int(*)[N])malloc(N*N*sizeof(int));
    init_matrix(*x);
}

我不会在 C++ 中推荐它——如果没有 C 的 VLA 特性,这种风格会很麻烦。在 C++ 中使用它可能更明智std::array&

于 2018-06-08T09:55:39.850 回答