【问题标题】:Initialize 2D array in constructor of CPP class在 C++ 类的构造函数中初始化二维数组
【发布时间】:2022-01-08 12:45:39
【问题描述】:

我想知道在 cpp 类中初始化二维数组的最佳方法是什么。在调用构造函数之前我不知道它的大小,即,

头文件包含:

private:
    int size;
    bool* visited;
    int edges;
    int** matrix;

默认构造函数(现在):

Digraph::Digraph(int n) {
  int rows = (n * (n-1)/2);
  int columns = 2;

  matrix = new int[rows][2];

  visited[size] = { 0 };

  size = n;
  edges = 0;
}

我想要的是一个 N 行 2 列的二维数组。

当我尝试编译时,当前返回 error: cannot convert 'int (*)[2]' to 'int**' in assignment

注意:我不能使用向量,所以请不要推荐它们。

【问题讨论】:

    标签: c++ arrays multidimensional-array


    【解决方案1】:

    matrix = new int[rows][2]; 不是有效的语法。分配一个二维稀疏数组需要多次new[] 调用,例如:

    private:
        int size;
        bool* visited;
        int edges;
        int** matrix;
        int rows;
        int columns;
    
    ...
    
    Digraph::Digraph(int n) {
      size = n;
      edges = 0;
    
      rows = (n * (n-1)/2);
      columns = 2;
    
      matrix = new int*[rows];
      for(int x = 0; x < rows; ++x) {
        matrix[x] = new int[columns];
        for(int y = 0; y < columns; ++y)
          matrix[x][y] = 0;
      }
    
      visited = new bool[size];
      for(int x = 0; x < size; ++x)
        visited[x] = false;
    }
    
    Digraph::~Digraph() {
      for(int x = 0; x < rows; ++x) {
        delete[] matrix[x];
      }
      delete[] matrix;
    
      delete[] visited;
    }
    

    或者,考虑将matrix 分配为一维数组,然后在访问其值时使用二维索引,例如:

    private:
        int size;
        bool* visited;
        int edges;
        int* matrix; // <-- 1 *, not 2 **
        int rows;
        int columns;
    
        int& matrix_value(int row, int col) { return matrix[(row * rows) + col]; }
    
    ...
    
    Digraph::Digraph(int n) {
      size = n;
      edges = 0;
    
      rows = (n * (n-1)/2);
      columns = 2;
    
      n = rows * columns;
      matrix = new int[n];
      for(int x = 0; x < n; ++x)
        matrix[n] = 0;
    
      visited = new bool[size];
      for(int x = 0; x < size; ++x)
        visited[x] = false;
    }
    
    Digraph::~Digraph() {
      delete[] matrix;
      delete[] visited;
    }
    

    无论哪种方式,您还需要根据Rule of 3/5/0 实现(或禁用)复制构造函数和复制赋值运算符,最好是移动构造函数和移动赋值运算符,例如:

    Digraph::Digraph(const Digraph &src) {
      size = src.size;
      edges = src.edges;
    
      rows = src.rows;
      columns = src.columns;
    
      matrix = new int*[rows];
      for(int x = 0; x < rows; ++x) {
        matrix[x] = new int[columns];
        for (int y = 0; y < columns; ++y)
          matrix[x][y] = src.matrix[x][y];
      }
    
      /* or:
      n = rows * columns;
      matrix = new int[n];
      for(int x = 0; x < n; ++x)
        matrix[n] = src.matrix[n];
      */
    
      visited = new bool[size];
      for(int x = 0; x < size; ++x)
        visited[x] = src.visited[x];
    }
    
    Digraph::Digraph(Digraph &&src) {
      size = 0;
      edges = 0;
      rows = 0;
      columns = 0;
      matrix = nullptr;
      visited = nullptr;
    
      src.swap(*this);
    }
    
    void Digraph::swap(Digraph &other) {
      std::swap(size, other.size);
      std::swap(edges, other.edges);
      std::swap(rows, other.rows);
      std::swap(columns, other.columns);
      std::swap(matrix, src.matrix);
      std::swap(visited, src.visited);
    }
    
    Digraph& Digraph::operator=(Digraph rhs) {
        Digraph temp(std::move(rhs));
        temp.swap(*this);
        return this;
    }
    

    话虽如此,更好的设计是使用std::vector 而不是new[],让它为您处理所有的内存管理和复制/移动,例如:

    #include <vector>
    
    private:
        int size;
        std::vector<bool> visited;
        int edges;
        std::vector<std::vector<int>> matrix;
        // or: std::vector<int> matrix;
        int rows;
        int columns;
    
    ...
    
    Digraph::Digraph(int n) {
      size = n;
      edges = 0;
    
      rows = (n * (n-1)/2);
      columns = 2;
    
      matrix.resize(rows);
      for(int x = 0; x < rows; ++x)
          matrix[x].resize(columns);
    
      /* or:
      matrix.resize(rows * columns);
      */
    
      visited.resize(size);
    }
    
    // implicitly-generated copy/move constructors, copy/move assignment operators,
    // and destructor will suffice, so no need to implement them manually...
    

    如果您不能使用std::vector,请考虑使用适当的语义实现您自己的vector 类,然后改用它。您应该通过使用为您实现 3/5 规则的类,尽可能地努力遵循 0 规则。

    【讨论】:

    • 这对我有用,非常感谢。是的,向量将是一个更好的解决方案,因为它可以为我处理所有内存。但不幸的是,目前我不允许使用它们。 ://
    • 你总是可以自己写vector类...
    • @Flip 虽然现在这听起来像是在浪费时间,但您将继续获得无法使用 std::vector 的任务,并且拥有一个可调整大小的数组类可以为您节省大量时间.不要等到你不得不为三个不同的任务破解相同的数组代码三次。编写一次,将其捆绑到一个类中,然后一遍又一遍地使用该类,直到您最终被允许使用std::vector 同样适用于std::string
    • @user4581301 虽然我很想能够做到这一点,但不幸的是,我们仅限于我们可以上传的内容,只允许上传某些文件,并且只允许使用某些类。否则,我会那样做。不过感谢您的提示!
    猜你喜欢
    • 1970-01-01
    • 2015-07-13
    • 2014-05-23
    • 2011-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多