Search code examples
c++vectorstdstdvector

pointer to pointer of vector yields 3D vector?


I have been looking through some legacy code and found this little snippet:

std::vector<int>** grid = new std::vector<int>*[10];
for (int k = 0; k < 10; k++) 
    grid[k] = new std::vector<int>[10];

And then later on, the original developer is calling this command here:

grid [i][j].push_back(temp);

I was under the impression that the [i][j] would return the value in the nested vector, but by using push_back implies that there is a pointer to a vector at that location? I'm confused where this third vector arises from.

Also, is there a better approach? would a triple nested vector also achieve the same results as the above code?

Thanks in advance!


Solution

  • grid[i][j] is a reference to a std::vector<int>.

    Rewriting things may clarify what you have.

    [Demo]

    #include <fmt/ranges.h>
    #include <vector>
    
    int main() {
        using line_t = std::vector<int>;  // line is a vector of ints
        using matrix_t = line_t*;  // matrix is an array of lines
        using grid_t = matrix_t*;  // grid is an array of matrices
    
        // Same as: grid_t grid{ new std::vector<int>*[3] };
        grid_t grid{ new matrix_t[3] };
        int v{};
        for (int k = 0; k < 3; k++) {  // we walk each matrix
            auto& matrix{ grid[k] };
            matrix = new line_t[3];
            for (int l = 0; l < 3; l++, v++) {  // we walk each line
                // Same as: auto& line{ grid[k][l] };
                auto& line{ matrix[l] };
                line = std::vector<int>(3, v);
            }
        }
    
        fmt::print("Grid\n\n");
        for (int k{0}; k < 3; k++) {
            fmt::print("Matrix {}\n", k);
            auto& matrix{ grid[k] };
            for (int l{0}; l < 3; l++) {
                auto& line{ matrix[l] };
                fmt::print("{}\n", line);
            }
            fmt::print("\n");
        }
    }
    
    
    // Outputs:
    //
    //   Grid
    //
    //   Matrix 0
    //   [0, 0, 0]
    //   [1, 1, 1]
    //   [2, 2, 2]
    //
    //   Matrix 1
    //   [3, 3, 3]
    //   [4, 4, 4]
    //   [5, 5, 5]
    //
    //   Matrix 2
    //   [6, 6, 6]
    //   [7, 7, 7]
    //   [8, 8, 8]
    

    Using std::vectors instead of built-in arrays would simplify things a lot.

    [Demo]

    #include <algorithm>  // fill
    #include <fmt/ranges.h>
    #include <vector>
    
    int main() {
        using line_t = std::vector<int>;  // line is a vector of ints
        using matrix_t = std::vector<line_t>;  // matrix is a vector of lines
        using grid_t = std::vector<matrix_t>;  // grid is a vector of matrices
    
        grid_t grid(3, matrix_t(3, line_t(3)));
        int v{};
        for (auto& matrix : grid) {
            for (auto& line : matrix) {
                std::ranges::fill(line, v++);
            }
        }
    
        fmt::print("Grid\n\n");
        for (int k{0}; k < 3; k++) {
            fmt::print("Matrix {}\n", k);
            fmt::print("{}\n\n", fmt::join(grid[k], "\n"));
        }
    }