【问题标题】:C++ initialize a 2D primitive array in a class with values from a constructorC ++使用来自构造函数的值初始化类中的二维原始数组
【发布时间】:2026-02-01 08:50:01
【问题描述】:

我正在尝试编译这段代码:

class OthelloState {
public: // constructor 

    Othello(int r, int c);

/* other stuff */

private: // private data

    const int rows;

    const int columns;

    int board[rows][columns];
}

我一直以:

OthelloState.h:109: error: invalid use of non-static data member 'OthelloState::rows'
OthelloState.h:115: error: from this location
OthelloState.h:115: error: array bound is not an integer constant
OthelloState.h:112: error: invalid use of non-static data member 'OthelloState::columns'
OthelloState.h:115: error: from this location
OthelloState.h:115: error: array bound is not an integer constant

我认为这意味着我必须将rowscolumns 设为静态。但是,如果我将它们设为静态,我将无法使用构造函数进行初始化,就像我必须为这个项目所做的那样......

我还有其他方法可以做到这一点吗?

PS:我知道在真正的奥赛罗棋中,棋盘是一个 8 x 8 的方格……但考虑到计算机在部分 8 x 8 格上生成下一个最佳棋步需要多长时间后,我们是不会玩“真正的”奥赛罗棋盘(即没有预定义的棋盘尺寸)。

【问题讨论】:

  • 不是static,而是“在编译时恒定且可确定”。
  • 不需要初始化rowscolumns吗?他们是consts。
  • @muntoo 我在 cpp 文件的构造函数中初始化了它们。

标签: c++ class compilation multidimensional-array


【解决方案1】:

在 C++ 中,不允许使用可变长度数组。 board[][] 需要在编译时知道它的两个维度。如果要在运行时初始化rowcol,可以使用vector<vector<int> > board;

class OthelloState {
public:
    OthelloState(int r, int c);

private: // private data
    const int rows;  // should be 'unsigned int'
    const int columns;

    vector<vector<int> > board;  
};

其他解决方案

假设您在编译时知道rowscols,那么您可以使用template。这与在构造函数中初始化 rowcol 一样好。

template<unsigned int row, unsigned int col>
class OthelloState {
public:
...
private:
  int board[row][col];
};

用法:

  OthelloState<8,8> obj;
  OthelloState<10,10> obj;

【讨论】:

  • 我可以在编译时不知道行和列的情况下使用你的模板方法吗?
  • @MatthewD,不可以。templates 只能与编译时信息一起使用。
  • vector&lt;vector&lt;int&gt; &gt; board[rows][columns];: 语法是 C++11 吗?
  • @EmileCormier,这是一个糟糕的复制粘贴。谢谢和编辑。
【解决方案2】:

如果它总是 8x8,那么常量是最小的解决方案。这是声明它的一种方法:

class OthelloState {
    // ...
private:
    enum { rows = 8, columns = 8 };
    int board[rows][columns];
};

【讨论】:

    【解决方案3】:

    但考虑到计算机生成需要多长时间 在部分 8 x 8 网格上的下一个最佳移动,我们不打算玩 使用“真正的”黑白棋棋盘(即没有预定义的棋盘尺寸)。

    我从那句话推断出你正在做家庭作业。如果是这种情况,那么您可能无法/不切实际地使用 Boost.MultiArray(除非您的讲师建议您可以使用 Boost)。

    剩下的vector&lt; vector&lt;int&gt; &gt; 是一个可以正确初始化的 PITA。在你甚至可以使用vector&lt; vector&lt;int&gt; &gt; 之前,你必须遍历每个内部向量并调整它的大小。

    Boost.MultiArray 基本上只是一维数据数组的过度包装。因此,我提出了第三种选择:围绕扁平的一维 vector 卷起您自己的 2D 包装器。您可以重载operator() 以模仿二维数组的[][] 行为:

    int operator()(size_t row, size_t col) {/*compute index into 1D array*/}

    我发布了这种包装器的示例here

    【讨论】:

      【解决方案4】:

      您正在尝试在运行时动态定义编译时固定大小数组的大小。您将需要动态分配内存。您还需要您的构造函数与您的类同名

      class OthelloState {
      public: // constructor 
      
      OthelloState(int r, int c)
      { 
         board = new int[r];
         for(int i = 0; i < r; i++)
         {
            board[i] = new int[c];
         }
      }
      
      
      /* other stuff */
      
      private: // private data
      
         const int rows;
      
         const int columns;
      
         int **board;
      };
      

      如果您使用此方法,请确保您在析构函数中为您的所有 news 匹配 deletes,但

      【讨论】:

      • 我不推荐这种方法。你只是要求悬空指针问题。您需要提供一个复制构造函数和复制赋值,以便进行深层复制(或者,将复制构造函数和赋值设为私有以使类不可复制)。
      • vector&lt; vector&lt;int&gt; &gt; 与此解决方案完全相同,没有所有内存管理陷阱。
      • 是的,需要适当的内存管理,但它是在运行时才知道大小时创建 primitive 二维数组的解决方案。我同意vector&lt; vector&lt;int&gt; &gt; 至少是创建 some 二维矩阵的一种更安全的方法,但我认为这不是问题的最佳答案。
      • 不应该是板子[i] = new int[c]; ?