Есть ли способ инициализировать массив с непостоянными переменными? (С++)

Я пытаюсь создать класс как таковой:

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, когда сам массив не является динамическим, просто размер не известно во время компиляции.

Ответ 1

Компилятор должен иметь точный размер класса при компиляции, вам придется использовать новый оператор для динамического выделения памяти.

Переключить массив char [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;
};

* EDIT: У меня был конструктор копирования и оператор присваивания

Ответ 2

использовать вектор.

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

Ответ 3

Не таким образом, как и в С++, размеры массива 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, см. здесь

Ответ 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";
}

Ответ 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;
};

Ответ 7

Вы можете выделить память для вашего 2-мерного массива в конструкторе и освободить его в деструкторе. Самый простой способ:

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

Если размер не известен во время компиляции, массив является динамическим. То, что вы можете сделать, чтобы сохранить его статичным, состоит в том, чтобы сделать их больше, чем ваш самый ожидаемый размер.

Ответ 9

Если вам нужен массив динамического размера как член класса, вам нужно массировать new его и присваивать этому значению указателю. Синтаксис char array[size] предназначен только для массивов статического размера.

Еще лучше, вы действительно должны использовать std::vector< std::vector<char> >, в настоящее время очень мало причин для ручной работы с массивами с динамическим размером.