0

I'm building a class that has an array variable, but I need to give the dimensions in the constructor to make the variable.

Some like:

class Table {
  int array[dim][dim];

  Table(int dim) {
    array[dim][dim]; //???
  }
}

What can I do?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Since this is C++ what you really need is `std::vector`. That's not an argument given to a constructor, `int[dim][dim]` is a *type*. – tadman Apr 08 '20 at 00:43
  • Do you need an int[] or can you use a std::vector? – MTLaurentys Apr 08 '20 at 00:43
  • See also: [why aren't variable length arrays a thing in C++](https://stackoverflow.com/questions/1887097/why-arent-variable-length-arrays-part-of-the-c-standard)? C++ needs to know the size of your `class` in advance. It can't randomly change. `sizeof(Table)` needs to be predictable. You could use `int**` but that's rife with other problems and unnecessarily side-steps a lot of the C++ tools already provided to solve this. – tadman Apr 08 '20 at 00:44

2 Answers2

1

What you need is to allocate the array dynamically at runtime.

You could use new[]/delete[] to allocate/free the array manually:

class Table {
  int **array;
  int arrDim;

  Table(int dim) : arrDim(dim) {
    array = new int*[dim];
    for(int i = 0; i < dim; ++i) {
        array[i] = new int[dim];
    }
  }

  ~Table() {
    for(int i = 0; i < arrDim; ++i) {
        delete[] array[i];
    }
    delete[] array;
  }
};

You would also need to manually implement an operator=, per the Rule of 3/5/0.

However, this issue is better handled using std::vector instead:

#include <vector>

class Table {
  std::vector<std::vector<int>> array;

  Table(int dim) : array(dim, std::vector<int>(dim)) {}
};

Or:

#include <vector>

class Table {
  std::vector<std::vector<int>> array;

  Table(int dim) {
    array.resize(dim);
    for(int i = 0; i < dim; ++i) {
        array[i].resize(dim);
    }
  }
};
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
0

If you are worry about speed and memory then it is better to use single continuous memory buffer for 2d arrays. Something like this.

Live Code

#include <stdint.h>
#include <cassert>
#include <vector>

template <class T>
class array_2d 
{
public:
    template<typename U>
    using ArrayT = std::vector<U>;
protected:
    ArrayT<T> m_buffer;
    uint32_t  m_rows;
    uint32_t  m_columns;

    inline uint32_t index(uint32_t row, uint32_t column) const {
        assert(row >= 0 && row < m_rows && column >= 0 && column < m_columns);
        return row*m_columns + column;
    }
public:
    array_2d(uint32_t rows, uint32_t columns) : m_rows(rows), m_columns(columns) { m_buffer.resize(rows*columns); }
    array_2d(uint32_t rows, uint32_t columns, const T & elem) : m_rows(rows), m_columns(columns) { m_buffer.resize(rows*columns, elem); }
    ~array_2d() = default;

    T &operator()(uint32_t row, uint32_t column) { return m_buffer[index(row, column)]; }
    T &at(uint32_t row, uint32_t column) { return operator()(row, column); }
    const T &operator()(uint32_t row, uint32_t column) const { return m_buffer[index(row, column)]; }
    const T &at(uint32_t row, uint32_t column) const { return operator()(row, column); }

    auto cbegin() const { return m_buffer.cbegin(); }
    auto cend() const { return m_buffer.cend(); }
    auto begin() { return m_buffer.begin(); }
    auto end() { return m_buffer.end(); }

    uint32_t size() const { return m_buffer.size(); }
};
DevO
  • 365
  • 1
  • 8