【问题标题】:Nice way to create a dynamic 2D matrix in C++ 11在 C++ 11 中创建动态二维矩阵的好方法
【发布时间】:2015-10-02 21:03:20
【问题描述】:

我已经知道如何使用new 创建动态二维矩阵并使用delete 释放它。由于 C++ 11 具有许多新的内存特性,例如 unique_ptrarray 容器等;什么是创建二维矩阵的好方法,这样就不需要使用delete 运算符显式释放矩阵?

【问题讨论】:

  • 你能澄清一下矩阵维度是否在编译时是已知的吗?
  • 是的,它们在编译时是已知的。

标签: c++ c++11


【解决方案1】:

最简单的方法之一是使用向量的向量

const int N = 10;
const int M = 10;
vector<vector<int>> matrix2d(N, vector<int>(M, 0)); // 10x10 zero-initialized matrix
matrix2d[0][0] = 42;

您当然可以使用单个向量并将其包装到访问器类中

vector<int> matrix(N * M, 0) // Ditto as above, but needs stride-aware accessors

为了完整起见,我将在此处发布一个小示例

template <typename T>
class Matrix2D {
    std::vector<T> data;
    unsigned int sizeX, sizeY;
public:
    Matrix2D (unsigned int x, unsigned int y)
        : sizeX (x), sizeY (y) {
        data.resize (sizeX*sizeY);
    }

    T& operator()(unsigned int x, unsigned int y) {
        if (x >= sizeX || y>= sizeY)
            throw std::out_of_range("OOB access"); // Throw something more appropriate
        return data[sizeX*y + x]; // Stride-aware access
    }
};

Live Example

或者也许将您的方式与smart pointer 结合起来。请注意,应谨慎使用vector&lt;vector&lt;int&gt;&gt; 方法,因为向量是相互独立的,并且没有强制要求它们应保持其大小固定。

【讨论】:

  • 最好使用单个向量 vector&lt;int&gt; matrix_data(N * M, 0) 由具有 2d 访问器的类包装
  • 我建议将其作为另一种解决方案。这具有易于理解和使用的优点,尽管它绝对不是最理想的。
  • 由于我在上面看到了很多方法,我突然想到,如果下面的方法是内存泄漏安全的。 #include #include using namespace std; int main() { size_t N = 10, M = 4;矢量 > my_arr(N); for(unsigned i = 0; i (M); for(unsigned i = 0; i
  • @AnirbanGhosh 使用 std::vector 是内存泄漏安全的,因为容器会为您管理分配和释放。
  • 抛出std::out_of_range,它继承自logic_error iirc。
【解决方案2】:

我强烈建议使用GSL 中的array_view,它最终将成为标准的一部分。

#include <array>
#include <vector>
#include "array_view.h" // must be manually imported until standardization

int main()
{
    std::array<int, 10>  arr{}; // 10 ints on the stack
    std::vector<int>  vec{12}; // 12 ints on the heap
    auto a = gsl::array_view<int, 2>{{2, 5}, arr}; // 2D, 2x5 matrix
    auto b = gsl::array_view<int, 3>{{3, 2, 2}, vec}; // 3D, 3x2x2 matrix
    auto c = gsl::array_view<int>{vec}; // 1D, spans from `begin()` to `end()`
    a[{0,3}] += b[{0,1,1}] * -c[2]; // access syntax
}

注意array_view 在它查看的范围的整个生命周期内无法控制。详情请参阅here

编辑:

array_view 已死,因为它在处理具有零成本抽象的多维数组时变得过于复杂。您应该改用GSL 中的span

有关跨度的更多信息,请参阅this

【讨论】:

  • 注:这个问题用 C++11 标记。不确定 OP 是否可以使用它。
  • @Marco GSL 支持 C++11,因为它是一个只有头文件的库,它只是一个包含。我觉得对这个问题有一个前瞻性的解决方案也很重要,因为这最终会成为标准。
  • 有道理。我也喜欢它
  • array 的大小必须在编译时已知。 OP 不清楚,但我认为他的意思是直到运行时才能知道大小
  • @M.M 好吧,只要排名不改变(如果改变了,无论如何大多数方法都需要不同的类型),可以通过更改 @987654331 的边界来模拟动态大小@。此外,array_view 适用于任何连续序列,包括向量(因此可以更改运行时)。
【解决方案3】:

基于上述答案,我找到了一种创建矩阵的简单方法,尽管不使用 C++11 功能。这是一个插图。

#include <iostream>
#include <vector>

using namespace std; 

typedef vector<vector<int>> Matrix2D;
typedef vector<Matrix2D> Matrix3D;

Matrix2D my_arr;

int main()
{
    const size_t N = 9;

    for(unsigned s = 4; s <= N; s++)
    {       
        my_arr.resize(s);
        for(unsigned i = 0; i < s; i++)
            my_arr[i].resize(s,s);

        for(unsigned i = 0; i < s; i++)
        {
            for(unsigned j = 0; j < s; j++)
                cout << my_arr[i][j] << " ";
            cout << endl;
        }

        cout << "\n\n";
    }
    return 0;
}

【讨论】:

  • 考虑到您想使用在编译时已知的数组,使用std::vector 是个坏主意。您应该至少使用 std::array 来代替。但是,我仍然强烈建议使用我的答案。
  • 谢谢。我想知道数组容器是否可以在需要时像向量一样调整大小。
  • 不,他们不能,但在这种情况下,您一开始就不需要编译时数组。编译时意味着它永远不会改变,这就是为什么std::array 会更受欢迎。否则std::vector 将是要走的路。但是,您仍应将其平放,否则您将遇到局部性问题。 (整数向量向量的向量(3D 矩阵)表示 3 指针在只需要 1 时取消引用。当您制作和迭代更大的矩阵时,这 咬你)
  • 我明白你的意思。非常感谢你。我会尝试按照你的方法。
  • 因为这基本上是我的回答,如果能获得一些分数会很好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-06
  • 1970-01-01
  • 2021-12-06
  • 2016-08-13
  • 2014-11-24
  • 1970-01-01
  • 2020-10-16
相关资源
最近更新 更多