Using Vector for a 2D Grid

How can I use std::vector to implement a simple 2D grid or matrix?

Using std::vector to implement a 2D grid or matrix is a common and efficient way to handle two-dimensional data in C++. There are primarily two approaches: using a vector of vectors, or using a single vector with custom indexing.

Approach 1: Vector of Vectors

This is the most straightforward approach, where we create a vector of vector elements:

#include <iostream>
#include <vector>

class Grid {
private:
  std::vector<std::vector<int>> data;
  size_t rows, cols;

public:
  Grid(size_t r, size_t c)
    : rows(r), cols(c),
      data(r, std::vector<int>(c, 0)){}

  int& at(size_t r, size_t c){
    return data[r][c];
  }

  const int& at(size_t r, size_t c) const{
    return data[r][c];
  }

  void print() const{
    for (const auto& row : data) {
      for (int val : row) {
        std::cout << val << ' ';
      }
      std::cout << '\n';
    }
  }
};

int main(){
  Grid grid(3, 4);

  // Set some values
  grid.at(0, 0) = 1;
  grid.at(1, 2) = 5;
  grid.at(2, 3) = 9;

  // Print the grid
  grid.print();
}
1 0 0 0
0 0 5 0
0 0 0 9

This approach is intuitive and allows for rows of different lengths if needed. However, it may have slightly more overhead due to multiple allocations.

Approach 2: Single Vector with Custom Indexing

This approach uses a single vector to store all elements, which can be more efficient:

#include <iostream>
#include <vector>

class Grid {
private:
  std::vector<int> data;
  size_t rows, cols;

public:
  Grid(size_t r, size_t c)
    : rows(r), cols(c), data(r * c, 0){}

  int& at(size_t r, size_t c){
    return data[r * cols + c];
  }

  const int& at(size_t r, size_t c) const{
    return data[r * cols + c];
  }

  void print() const{
    for (size_t i = 0; i < rows; ++i) {
      for (size_t j = 0; j < cols; ++j) {
        std::cout << at(i, j) << ' ';
      }
      std::cout << '\n';
    }
  }
};

int main(){
  Grid grid(3, 4);

  // Set some values
  grid.at(0, 0) = 1;
  grid.at(1, 2) = 5;
  grid.at(2, 3) = 9;

  // Print the grid
  grid.print();
}
1 0 0 0
0 0 5 0
0 0 0 9

This approach uses a single allocation and can be more cache-friendly, potentially offering better performance for large grids.

Advanced Features

You can extend either approach with more advanced features:

Range Checking

Add bounds checking in the at() function:

int& at(size_t r, size_t c){
  if (r >= rows || c >= cols) {
    throw std::out_of_range(
      "Grid indices out of range");
  }
  return data[r * cols + c];
}

Iterators

Implement custom iterators for row-wise or column-wise traversal.

Resizing

Add functions to resize the grid:

void resize(size_t new_rows, size_t new_cols){
  std::vector<int> new_data(
    new_rows * new_cols, 0);
  for (size_t i = 0; i <
       std::min(rows, new_rows); ++i) {
    for (size_t j = 0; j <
         std::min(cols, new_cols); ++j) {
      new_data[i * new_cols + j] = at(i, j);
    }
  }
  data = std::move(new_data);
  rows = new_rows;
  cols = new_cols;
}

Operations

Implement mathematical operations like matrix addition or multiplication.

Remember, the choice between these approaches depends on your specific use case. The vector of vectors is more flexible but might be slightly slower, while the single vector approach is generally faster but less flexible for non-rectangular grids.

Dynamic Arrays using std::vector

Explore the fundamentals of dynamic arrays with an introduction to std::vector

Questions & Answers

Answers are generated by AI models and may not have been reviewed. Be mindful when running any code on your device.

Storing Polymorphic Types in std::vector
How can I store polymorphic types in a std::vector?
Removing Objects from std::vector
How can I remove objects from a std::vector?
Removing Elements from the Middle of a Vector
How can I efficiently remove elements from the middle of a std::vector?
Implementing a Circular Buffer with Vector
How do I implement a circular buffer using std::vector?
Using Vector with Move-Only Types
Can I use std::vector with move-only types like std::unique_ptr?
Thread Safety with std::vector
How can I safely access std::vector elements in a multithreaded environment?
Or Ask your Own Question
Get an immediate answer to your specific question using our AI assistant