Search code examples
c++global-variablesextern

Looking up global variables instead of constructing them inside a c++ function


Question:

I have some functions that are being called a lot. Inside each function, local variables are constructed. These variables are usually Eigen::MatrixXds that are sort of small (usually under 10 x 10). Every call constructs the same variable, over and over again, then discards it.

I started thinking it would be faster to define these variables outside of the function, and then look them up.

  1. Why is the "looking up" of some global variable likely to be faster than re-constructing it over and over again?
  2. Should I put the global constants in a namespace? What could go wrong with this approach?

First Code:

I started off with these three files.

First: functions.h

#ifndef FUNCTIONS_H
#define FUNCTIONS_H

#include <Eigen/Dense>

Eigen::MatrixXd getMatrix();

#endif //FUNCTIONS_H

second: functions.cpp

#include "functions.h"

Eigen::MatrixXd getMatrix()
{
    Eigen::MatrixXd myMatrix(4,4);
    for(int i = 0; i < 4; ++i)
    {
        myMatrix(i,i) = 3.0;
    }
    return myMatrix;
}

Third, main.cpp

#include "functions.h"

int main()
{

    for(int i = 0; i < 500000; ++i)
        getMatrix();

    return 0;
}

Second Code:

First, functions2.h:

#ifndef FUNCTIONS2_H
#define FUNCTIONS2_H

#include <Eigen/Dense>

extern const Eigen::MatrixXd myMatrix;

Eigen::MatrixXd getMatrix2();

#endif //FUNCTIONS2_H

then functions2.cpp

#include "functions2.h"

const Eigen::MatrixXd myMatrix = Eigen::MatrixXd::Identity(2,2);

Eigen::MatrixXd getMatrix2()
{
    return myMatrix;
}

then a different main.cpp

#include "functions2.h"

int main()
{

    for(int i = 0; i < 500000; ++i)
        getMatrix2();

    return 0;
}

Solution

  • If your get functions will always be returning the same matrix, you can generate it once the first time it is needed, without using a global variable, by using a static local one.

    Eigen::MatrixXd getMatrix()
    {
       static Eigen::MatrixXd myMatrix{[](){
            Eigen::MatrixXd m(4,4);
            for(int i = 0; i < 4; ++i)
            {
                m(i,i) = 3.0;
            }
            return m;
        }};
        return myMatrix;
    }
    

    This uses a lambda function to initialize the matrix, rather than another function. It will also create a copy of the matrix every time, but the original matrix is hidden from all users and cannot be changed. Copy elision cannot happen here, since the source is not a non-static local variable. RVO can still be done.

    Another option here is to return a reference to the matrix, by changing the function to

    const &Eigen::MatrixXd getMatrix()
    

    This will avoid the copy and still hides the original matrix from changes unless the caller applies a const_cast to the returned value.

    For getMatrix2, you can just move the global variable you have into getMatrix2 as a static.