【问题标题】:Is there a way to initialize an array with non-constant variables? (C++)有没有办法用非常量变量初始化数组? (C++)
【发布时间】:2009-06-09 21:53:57
【问题描述】:

我正在尝试创建一个这样的类:

class CLASS
{
public:
    //stuff
private:
    int x, y;
    char array[x][y];
};

当然,除非我将int x, y; 更改为

const static int x = 10, y = 10;

这是不切实际的,因为我试图从文件中读取 x 和 y 的值。那么有没有办法用非恒定值初始化一个数组,或者声明一个数组并在不同的语句上声明它的大小?而且我知道这可能需要创建一个数组类,但是我不确定从哪里开始,当数组本身不是动态的时,我不想创建一个 2D 动态列表,只是大小是在编译时未知。

【问题讨论】:

    标签: c++ arrays


    【解决方案1】:

    使用矢量。

    #include <vector>
    class YourClass
    {
    public:
        YourClass()
        : x(read_x_from_file()), y(read_y_from_file())
        {
            my_array.resize(x);
            for(int ix = 0; ix < x; ++ix)
                my_array[ix].resize(y);
        }
    
        //stuff
    
    private:
        int x, y;
        std::vector<std::vector<char> > my_array;
    };
    

    【讨论】:

    • 作为“严格标准”的解决方案不错,但boost::multi_array 肯定也值得一提?
    • 您可以在没有循环的情况下进行所有内联操作:: x(read_x_from_file()), y(read_y_from_file()), my_array(x, vector&lt;char&gt;(y)) {}。也就是说,我会在 ctor 的主体中进行文件读取和分配。我尝试将 ctor-initializer 的副作用保持在绝对最低限度。
    • use vector. 当我调用的函数具有数组签名时,这是一个怎样的选项? ://
    【解决方案2】:

    编译器在编译时需要有确切的类大小,你必须使用new操作符来动态分配内存。

    切换字符数组[x][y];到 char** 数组;并在构造函数中初始化你的数组,不要忘记在析构函数中删除你的数组。

    class MyClass
    {
    public:
        MyClass() {
            x = 10; //read from file
            y = 10; //read from file
            allocate(x, y);
        }
    
        MyClass( const MyClass& otherClass ) {
            x = otherClass.x;
            y = otherClass.y;
            allocate(x, y);
    
            // This can be replace by a memcopy
            for( int i=0 ; i<x ; ++i )
                for( int j=0 ; j<x ; ++j )
                    array[i][j] = otherClass.array[i][j];
        }
    
        ~MyClass(){
            deleteMe();
        }
    
        void allocate( int x, int y){
            array = new char*[x];
            for( int i = 0; i < y; i++ )
                array[i] = new char[y];
        }
    
        void deleteMe(){
            for (int i = 0; i < y; i++)
               delete[] array[i];
            delete[] array;
        }
    
        MyClass& operator= (const MyClass& otherClass)
        {
            if( this != &otherClass )
            {
                deleteMe();
                x = otherClass.x;
                y = otherClass.y;
                allocate(x, y);
                for( int i=0 ; i<x ; ++i )
                    for( int j=0 ; j<y ; ++j )
                        array[i][j] = otherClass.array[i][j];            
            }
            return *this;
        }
    private:
        int x, y;
        char** array;
    };
    

    *编辑: 我有复制构造函数 和赋值运算符

    【讨论】:

    • 并访问一个特定的元素我可以说 array[xpos][ypos];?
    • 是Keand64,只需使用array[xpos][ypos];
    • 那很糟糕。复制构造怎么样。赋值运算符。为什么不将所有内存放在一个连续的块中而不是一组数组中。构造函数中的异常处理呢。
    • 要访问元素 [xPos][yPos],您需要编写一个接受两个参数并返回对数组成员中正确元素的引用的方法。: char& CLASS::date(int x, int y) {返回数组[x][y];}
    • 马丁,你是对的,我已经考虑了你的评论。 Personnaly 我肯定会使用向量(正如 aaron 提到的那样),但由于问题的标题是“有没有办法用非常量变量初始化数组?”,我已经写了一个与这个问题相对应的答案。
    【解决方案3】:

    不像在 c++ 中那样,c 样式的数组大小必须在编译时知道,一些供应商特定的扩展允许某些运行时大小(以增强与 C99 的兼容性),但在您描述的情况下不是(如果你有兴趣,here's a description)。最简单的做法是:

    std::vector< std::vector<char> > array;
    

    并在构造函数中应用大小:

    array.resize(x);
    for(std::vector< std::vector<char> >::iterator curr(array.begin()),end(array.end());curr!=end;++curr){
       curr->resize(y);
    }
    

    vector 相对于 c 风格的数组有很多优点,见here

    【讨论】:

      【解决方案4】:

      将所有内存放在一个块中。
      因为它是私有的,所以您可以获取访问方法来检索正确的值。

      快速示例:

      #include <vector>
      #include <iostream>
      
      class Matrix
      {
          public:
          class Row
          {
              public:
              Row(Matrix& p,unsigned int x)
                  :parent(p)
                  ,xAxis(x)
              {}
              char& operator[](int yAxis)
              {
                  return parent.data(xAxis,yAxis);
              }
              private:
                  Matrix&         parent;
                  unsigned int    xAxis;
          };
      
          Matrix(unsigned int x,unsigned int y)
              :xSize(x)
              ,ySize(y)
              ,dataArray(x*y)
          {}
      
          Matrix::Row operator[](unsigned int xAxis)
          {
              return Row(*this,xAxis);
          }
          char& data(unsigned int xAxis,unsigned int yAxis)
          {
              return dataArray[yAxis*xSize + xAxis];
          }
          private:
              unsigned int xSize;
              unsigned int ySize;
              std::vector<char>   dataArray;
      };
      
      
      int main()
      {
          Matrix      two(2,2);
      
          two[0][0]   = '1';
          two[0][1]   = '2';
          two[1][0]   = '3';
          two[1][1]   = '4';
      
          std::cout <<  two[1][0] << "\n";
          std::cout <<  two.data(1,0) << "\n";
      }
      

      【讨论】:

        【解决方案5】:

        【讨论】:

          【解决方案6】:

          您不能使用非常量值(编译时)以声明方式分配或初始化全局或静态数组。但是对于局部数组是可能的(C99 可变大小的数组,因为它们的初始化程序基本上在每次执行函数时都在运行时运行)。

          对于您的情况,我建议使用指针而不是数组,并在运行时动态创建实际数组(使用new):

          class CLASS
          {
          public:
              CLASS(int _x, int _y) : x(_x), y(_y) {
                 array = new char*[x];
                 for(int i = 0; i < x; ++i)
                     array[i] = new char[y];
              }
              ~CLASS() {
                 for (int i = 0; i < x; ++i)
                     delete[] array[i];
                 delete[] array;
              }
              //stuff
          private:
              int x, y;
              char **array;
          };
          

          【讨论】:

          • 我说的是分配和初始化,一般来说。大小未知的数组是动态的。你不能在不知道数量的情况下神奇地静态分配内存。
          • 那很糟糕。复制构造怎么样。赋值运算符。为什么不将所有内存放在一个连续的块中而不是一组数组中。构造函数中的异常处理呢。
          • 你是对的,但我并没有展示实现数组的所有最佳实践。我添加了代码 sn-p 作为对有关“动态数组”的详细说明的响应。
          【解决方案7】:

          您可以在构造函数中为二维数组分配内存,并在析构函数中释放它。最简单的方法:

          array = (char **)malloc(sizeof(char *) * x);
          if (array) {
              for (i = 0; i < x; i++) {
                  array[i] = (char *)malloc(sizeof(char) * y);
                  assert(array[i]);
              }
          }
          

          【讨论】:

            【解决方案8】:

            如果在编译时大小未知,则数组是动态的。您可以做的保持它静止的方法是使它们大于您的最大预期尺寸。

            【讨论】:

            • 如果该大小超过堆栈帧中的可用空间(通常为 4k),则会导致编译错误。
            【解决方案9】:

            如果您想要一个动态大小的数组作为类成员,您需要将new 排列成数组并将该值分配给一个指针。 char array[size] 语法用于静态大小的数组。

            更好的是,您真的应该使用std::vector&lt; std::vector&lt;char&gt; &gt;,如今手动处理动态大小的数组的充分理由很少。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-03-23
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2022-11-12
              相关资源
              最近更新 更多