Short square matrix class in C++ using an array
(1) The exception is a good way of handling such errors, but it may be a good idea to provide a non-throwing, less safe accessors. For example, std::vector::at() will throw an std::out_of_range if requested index is not valid, but std::vector::operator[] will silently accept all values. That's because, if individual elements are accessed very frequently (some complicated math algorithm), all those ifs may impact the performance. So, as it goes for the exceptions, two suggestions:


throw std::out_of_range instead of plain std::exception to indicate what kind of error just happened,
do not throw in every accessor (you only have one, which leads to point 4, see below).


(2) Yes, they do. But, the basic question is: do you really need to be able to specify size of a matrix at runtime? Perhaps it would be better to use compile-time constant size:

template &lt;size_t Size&gt;
class Matrix
{
private:
  int elements[Size*Size];
  //...
};


Then, you would use it this way:

Matrix&lt;4&gt; mat4;


In this version, no destructor would be necessary and no memory allocation required. Because of that, this version also can be faster.

(3) "Idiomatic C++ style" has become a very fragile term recently (IMHO). But, you could probably provide support for accessing elements of your matrix using operator[] (see point 4).

(4) It would be nice if users of your Matrix could write simply:

Matrix&lt;4&gt; mat; // Or: Matrix mat {4}, in dynamically-allocated version
mat[3][3] = 1; // set elements in row 3, column 3 (note, that indices are from 0 to 3)


Or, equivalently, in simpler version:

mat[15] = 1;


(*) Simple version only requires the presence of operator[]:

template &lt;size_t Size&gt;
class Matrix
{
    int&amp; operator[](size_t index)
    {
        return elements[index];
    }

    const int&amp; operator[](size_t index) const
    {
        return elements[index];
    }
};


Note, that two version are provided, so you can do this:

Matrix&lt;4&gt; mat;
mat[5] = 1;


but not this:

const Matrix&lt;4&gt; constMat;
constMat[2] = 3; // compilation error: cannot assign to const reference


(**) The more elegant, but also more difficult version (nested [][] syntax), requires, that operator[] of the matrix must return an object (or an array) that also supports [] notation.

The easier way to achieve this would be to to change the T* elements to T** elements (or, in templated version, elements[Size*Size] to elements[Size][Size]). Note, that in this case you do not need the convert() function, since you can use the indices explicitly.

You could also declare simple Vector struct (I will limit myself here to templated version):

template &lt;size_t Size&gt;
struct Vector
{
private:
  int elements[Size];

public:
  int&amp; operator[](size_t index)
  {
    return elements[index];
  }

  const int&amp; operator[](size_t index) const
  {
    return elements[index];
  }
};


And then implement your Matrix using Vector:

template &lt;size_t Size&gt;
class Matrix
{
private:
  Vector&lt;Size&gt; columns[Size];

public:
  Vector&lt;Size&gt;&amp; operator[](size_t index)
  {
    return columns[index];
  }

  const Vector&lt;Size&gt;&amp; operator[](size_t index) const
  {
    return columns[index];
  }
};


(1.1) Now, after we covered the topic of operator[], we can return to the exceptions once more. To aid those unsafe operator[]s, we can add more safe, explicit at() function:

template &lt;size_t Size&gt;
class Matrix
{
private:
  Vector&lt;Size&gt; columns[Size];

public:
  Vector&lt;Size&gt;&amp; at(size_t index)
  {
    if (index &gt;= Size) throw std::out_of_range("Invalid index!");
    return columns[index];
  }

  const Vector&lt;Size&gt;&amp; at(size_t index) const
  {
    if (index &gt;= Size) throw std::out_of_range("Invalid index!");
    return columns[index];
  }
};