Search code examples
c++arraysfunctionpointersreturn

warning: address of local variable 'angles' returned [-Wreturn-local-addr]


I'm trying to return float x, y and z angle values for a body object from my ODE (open dynamics engine) simulation.

float* Creature::eulerAngles(const float &q0, const float &q1, const float &q2, const float &q3){

    float angles[3] = {atan2(2 * (q0*q1 + q2*q3), 1 - 2 * (q1*q1 + q2*q2)),
                      asin( 2 * (q0*q2 - q3*q1)),
                      atan2(2 * (q0*q3 + q1*q2), 1 - 2 * (q2*q2 + q3*q3))};
    return angles;
}

Because dBodyGetQuaternion returns 4 const float quaternions I need to then get the rotations and I've had immense difficulty trying to get it to compile. Now it does compile but I'm getting this warning.

Could anyone explain to me why and what it means please?


Solution

  • float angles[3] = { ... };
    

    defines a local array.

    The statement

    return angles;
    

    returns a pointer to the first element of the array.

    However, the array is destructed as soon as the function returns. Hence, the returned pointer is a dangling pointer.

    That's what the compiler is warning you about. If you dereference the returned pointer in the calling function, you invoke undefined behavior.

    In order to return a pointer to an array that will remain valid after the function returns, you need to allocate dynamic memory and return the dynamic memory.

    float* Creature::eulerAngles(const float &q0, const float &q1,
                                 const float &q2, const float &q3)
    {
       float* angles = new float[3];
       angles[0] = atan2(2 * (q0*q1 + q2*q3), 1 - 2 * (q1*q1 + q2*q2));
       angles[1] = asin( 2 * (q0*q2 - q3*q1));
       angles[2] = atan2(2 * (q0*q3 + q1*q2), 1 - 2 * (q2*q2 + q3*q3));
    
       return angles;
    }
    

    Keep in mind that if you do the above, you'll have to make sure to call delete [] on the returned pointer in the calling function.

    To avoid the hassles of manually allocating and deallocating memory, you can use std::vector<float> as your return type.

    std::vector<float> Creature::eulerAngles(const float &q0, const float &q1,
                                             const float &q2, const float &q3)
    {
       std::vector<float> angles(3);
       angles[0] = atan2(2 * (q0*q1 + q2*q3), 1 - 2 * (q1*q1 + q2*q2));
       angles[1] = asin( 2 * (q0*q2 - q3*q1));
       angles[2] = atan2(2 * (q0*q3 + q1*q2), 1 - 2 * (q2*q2 + q3*q3));
    
       return angles;
    }
    

    With this, memory management is done automatically for you.

    Since the size of the array is fixed at 3, using std::array<float, 3> is better than using std::vector<float>:

    std::array<float, 3> Creature::eulerAngles(const float &q0, const float &q1, const float &q2, const float &q3)
    {
       std::array<float, 3> angles;
       angles[0] = atan2(2 * (q0*q1 + q2*q3), 1 - 2 * (q1*q1 + q2*q2));
       angles[1] = asin( 2 * (q0*q2 - q3*q1));
       angles[2] = atan2(2 * (q0*q3 + q1*q2), 1 - 2 * (q2*q2 + q3*q3));
    
       return angles;
    }