有没有一种方法可以使用非常量变量初始化数组?(C++)

12

我正在尝试创建一个类,如下所示:

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动态列表,只是大小在编译时未知。

9个回答

15

使用向量(vector)。

#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;
};

1
作为一个“严格标准”的解决方案很好,但是boost::multi_array也值得一提吧? - Pavel Minaev
你可以在不使用循环的情况下完成所有内联操作:: x(read_x_from_file()), y(read_y_from_file()), my_array(x, vector<char>(y)) {}。话虽如此,我会将文件读取和分配都放在构造函数的主体中进行。我尽量将构造函数初始化器产生的副作用降到最低。 - Johannes Schaub - litb
使用向量。当我调用的函数签名为数组时,这是一个选项吗? :/ - n611x007

10

编译器在编译时需要准确的类大小,因此您需要使用new运算符动态分配内存。

将char array[x][y]; 更改为char ** array; 并在构造函数中初始化数组,不要忘记在析构函数中删除数组。

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]来访问特定的元素吗? - user98188
4
好的,我会尽力为您进行翻译。这很糟糕。复制构造函数和赋值运算符怎么样?为什么不把所有的内存放在一个连续的块中,而不是一个数组的数组中?构造函数中的异常处理怎么样? - Martin York
1
马丁,你说得对,我已经考虑了你的评论。个人而言,我肯定会使用向量(正如亚伦所提到的),但由于问题的标题是“有没有一种方法可以用非常量变量初始化数组?”,所以我写了一个相应的答案。 - Steve Gury
不是要竞争什么的,虽然我已经发布了一个竞争性答案,但你还没有修复这里的内存泄漏和赋值运算符中的缓冲区溢出。踩个负分。当代码可靠地工作时,我很乐意将其改为正分。 - Aaron
这是一个非常适合使用复制/交换技术的理想场景 :) 可以大大减少代码行数。 - Johannes Schaub - litb
显示剩余3条评论

4

不是像c++那样,c风格的数组大小必须在编译时知道,在某些供应商特定扩展中允许某些运行时大小(以增强与C99的兼容性),但不是在您描述的情况下(如果您感兴趣,这里有一个说明)。最简单的方法是:

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);
}

相较于C风格数组,向量有许多优势,请参见此处


2

将所有内存放入一个块中。
因为它是私有的,你可以使用访问方法来检索正确的值。

快速示例:

#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";
}

2

1

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

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

1

你不能使用非常量值(编译时)声明式地分配或初始化全局或静态数组。但对于局部数组来说是可能的(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;
};

我通常谈论分配和初始化。大小未知的数组是动态的。你不能在不知道数量的情况下神奇地静态分配内存。 - Mehrdad Afshari
1
那很糟糕。复制构造函数怎么样?赋值运算符呢?为什么不把所有内存放在一个连续的块中,而不是一个数组中的数组?构造函数中的异常处理怎么办? - Martin York
你说得对,但我在实现数组时并没有展示所有最佳实践。我添加了代码片段作为对“动态数组”请求的详细说明的响应。 - Mehrdad Afshari

0
如果在编译时不知道大小,则数组是动态的。为了使它们保持静态,您可以将它们设置为大于您预期最大大小的值。

如果大小超过堆栈帧中可用的空间(通常为4k),则会导致编译错误。 - Not Sure

0
如果你想要一个动态大小的数组作为类成员,你需要使用new来创建一个数组,并将该值分配给指针。 char array[size]语法仅适用于静态大小的数组。
更好的方法是,你应该使用std::vector< std::vector<char> >,现在很少有好的理由手动处理动态大小的数组。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接