handy
handy

Reputation: 1076

Return Eigen::VectorXd by reference from function

I'd like to return an Eigen::Vector from a function and wondering what's the proper way to do it. Something like

Eigen::VectorXd& getMesh(int N) {
    Eigen::VectorXd mesh(N + 1);  // nb. of nodes
    // Nodes are equally spaced
    for (int i = 0; i < N + 1; i++) {
        mesh[i] = i * (1.0 / N);
    }

    return mesh;
}

int main() {
    // Mesh with 100 cells
    Eigen::VectorXd mesh = getMesh(100);

    return 0;
}

Now of course, we might get into problems here since the memory used to create the mesh vector in getMesh() might not be dynamically allocated i.e. when we return from the function, out reference "points" to deleted memory.

I could allocate the memory inside the main function and then pass it to the getMesh function, but is that considered fine? What other possibilities would I have?

Upvotes: 3

Views: 2017

Answers (1)

Louen
Louen

Reputation: 3677

You must not return a reference to a local variable of your function. This is called a dangling reference. Note that your compiler should give you a warning when you do this : e.g Visual Studio.

warning C4172: returning address of local variable or temporary: mesh

The problem with your current getMesh() function is that the local variable mesh gets allocated on the stack in the function execution. Then you return a reference to it in main, but the stack memory where mesh was allocated is freed when the getMesh() function exits. This means it will very likely get overwritten by later data in your program.

Note that this issue will happen even if the memory used to store the coordinates stored in your vector. Your mesh variable is an instance of a class (VectorXd) with several member variables. One of them will be the size of your vector, and the other a pointer to the dynamically-allocated storage for your vector's data.

This is an example of what VectorXd's definition could look like

class FakeVectorXd {
    int current_size;
    int max_size;
    double* data;
};

When you create mesh, the member variables current_size, max_size and data are allocated locally on the stack. Then in the vector's constructor data's value is set to point to a dynamically allocated memory area to store your vector's coordinates. When you return from getMesh(), the stack location where current_size, max_size and data live in memory is now marked as available and they will be overwritten.

What you can do is simply return the VectorXd by value. This is perfectly fine:

Eigen::VectorXd getMesh(int N) {
    Eigen::VectorXd mesh(N + 1);
    for (int i = 0; i < N + 1; i++) {
        mesh[i] = i * (1.0 / N);
    }
    return mesh;
}

Upvotes: 5

Related Questions