C++ using vector<vector> to represent matrix with continuous data buffer

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

vector<vector<float>> func(int M)
{
    // res = matrix size MxM
    vector<vector<float>> res;
    float* buffer = static_cast<float*>(malloc(M * M * sizeof(float)));
    res.reserve(M);
    for (int i=0; i<M; i++) {
        res.emplace_back(buffer + i * M, buffer + (i + 1) * M);
        /// res[i] = compute_the_matrix();
    }
    
    return res;
}

I’m required to make a function that use vector<vector<float>> to represent a matrix. However, it’s inefficient because the rows might be at different location in memory, while a good matrix should have all its element in a continuous block.

To do this, I malloc a continuous block of memory. Then initialize the vectors from this block.

Is this method safe and will the vectors free memory correctly when it’s destructed? Another situation I can think of is if there’s an exception in res[i] = compute_the_matrix();, then we have a memory leak.

Edit: I think this code perform copy-constructor instead of move-constructor, so it’s not what I’m looking for. So, how can I make a vector that is continuous in memory?

>Solution :

The code doesn’t do what you think it does.

The line

res.emplace_back(buffer + i * M, buffer + (i + 1) * M);

creates a new std::vector<float> to add to res. This std::vector<float> will allocate its own memory to hold a copy of the data in the range [buffer + i * M, buffer + (i + 1) * M), which also causes undefined behavior because you never initialized the data in this range.

So, in the end you are not using the memory you obtained with malloc at all for the vectors. That memory is simply leaked at the end of the function.


You can’t specify what memory a vector<vector<float>> should use at all. There is simply no way to modify its allocation strategy. What you can do is etiher use a vector<float> instead to hold the matrix entries linearly indexed in a single vector or you can use a vector<vector<float, Alloc1>, Alloc2> where Alloc1 and Alloc2 are some custom allocator types for which you somehow specify the allocation behavior so that the storage layout is closer to what you want (although I doubt that the latter can be done nicely here or is worth the effort over just using the linear representation).

Leave a Reply