Matrix Implementation and Operations in C++ – Part 1

A safer C++11 matrix implementation using contiguous storage, RAII, templates, and basic operations such as addition, multiplication, transpose, and identity matrices.

Matrix Class Using Templates

The integer matrix solved the ownership problem, but image processing and numerical code rarely use only int. Pixels may be unsigned char, convolution kernels may be float, and geometry transforms are often double.

A template lets the same matrix structure work for several value types. For this tutorial, the class is intentionally restricted to arithmetic types using static_assert. A more general production matrix might support custom numeric types, but that adds requirements about construction, multiplication, and formatting that distract from the implementation.

A Complete C++11 Template Matrix

The following class keeps the same row-major storage rule from Page 1. It adds initializer-list construction, addition, subtraction, scalar multiplication, matrix multiplication, transpose, an identity matrix helper, and stream printing.

There are a few deliberate choices in this implementation:

  • The class follows the Rule of Zero. It does not define a destructor, copy constructor, move constructor, or assignment operator because std::vector already handles ownership correctly.
  • The initializer-list constructor checks that every row has the same length. Without that check, a visual matrix literal could silently become a broken rectangular matrix.
  • Addition and subtraction reuse compound operators. That keeps the shape check in one place.
  • Matrix multiplication checks left.cols() == right.rows(). This is the most common rule to forget when writing quick test code.
  • The multiplication loop uses row, shared, and col names instead of single-letter indexes. In real code reviews, names like these make dimension mistakes easier to see.

Using The Template Matrix

Here is a small example that exercises the operations. The matrices are double, but the same class can also be used with int, float, or other arithmetic types.

The output is:

This is a small implementation, but it is already much safer than the pointer-to-pointer version. Invalid dimensions are rejected before the operation runs. Indexing mistakes throw exceptions instead of walking into unrelated memory. Copying a matrix copies a vector, and returning a matrix by value is natural.

Where This Design Is Good Enough

This kind of matrix class is useful for learning, small tools, tests, simple image-processing experiments, and code where clarity matters more than squeezing every cycle. It also gives you a clean place to add project-specific behavior such as clamping, convolution helpers, CSV export, or debug printing.

For serious numerical work, large image pipelines, sparse matrices, SIMD-heavy operations, or GPU processing, use a mature library. Libraries such as Eigen and OpenCV have years of optimization and edge-case handling behind them. The value of writing a matrix class yourself is learning the design constraints and avoiding the old memory-management traps, not replacing a production linear algebra library.

Practical Takeaways

Prefer one contiguous buffer over a pointer-to-pointer matrix unless you have a specific reason not to. Keep the dimensions inside the object so operations can validate their inputs. Put the indexing formula in one helper function. Let std::vector own the memory. Add templates only after the non-template design is clear.

That is the difference between code that merely works in a tutorial and code that still looks reasonable when you return to it months later.

Saeid Yazdani working at an electronics workbench
Saeid Yazdani

Embedded Systems Engineer with 15+ years of professional experience developing firmware, electronics, measurement systems, and hardware-software solutions. I have been programming for more than two decades and write about Embedded C/C++, STM32, AURIX, PCB design, debugging, and practical engineering lessons from real-world projects.

Articles: 38

Leave a Reply

Your email address will not be published. Required fields are marked *