警告:返回局部变量'angles'的地址[-Wreturn-local-addr]。

6

我正在尝试从我的ODE(开放动力学引擎)模拟中返回一个物体对象的浮点型x、y和z角度值。

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;
}

因为dBodyGetQuaternion返回4个const float四元数,所以我需要获得旋转角度,但是我一直很难编译它。现在它可以编译了,但我收到了这个警告。请问有人能解释一下这是什么意思吗?

1
错误信息非常明确。您正在返回angles的地址,但是在您返回之后,angles不再存在。那么调用者应该如何处理一个不存在的对象的地址呢? - David Schwartz
好的,谢谢你解释清楚了 :) - Jade
3个回答

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

定义了一个本地数组。

该语句

return angles;

返回指向数组第一个元素的指针。

然而,该数组在函数返回时被销毁。因此,返回的指针是悬空指针。

这就是编译器警告你的原因。如果在调用函数中对返回的指针进行解引用,则会引发未定义行为。

为了返回一个在函数返回后仍将保持有效的数组指针,您需要分配动态内存并返回该动态内存。

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;
}

谨记,如果你按照以上方法做,你必须确保在调用函数中调用delete []释放返回的指针。

为避免手动分配和释放内存的麻烦,您可以使用std::vector<float>作为返回类型。

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;
}

有了这个,内存管理就由程序自动完成。

由于数组大小在3时已经固定,所以使用std::array<float, 3>比使用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;
}

2
array<float, 3> 可能是合适的,因为每次返回的大小似乎都相同。 - M.M
2
这个很好用,感谢您提供深入的解释。我只使用C++几个月,仍然对指针的工作原理感到困惑,因此非常感谢您的帮助和建议。 - Jade
1
@Jade,我很高兴能够帮助你。祝你编程愉快。 - R Sahu

2
警告信息准确地指出了问题所在:你正在返回指向本地数组 angles 的指针。
无论是简单的 int 变量还是像你的数组一样的数组,局部变量在函数返回时都会失效。这意味着它们会消失。拥有这样一个变量的指针意味着你不能再使用该指针,因为它不再指向该变量占用的内存。使用它将导致未定义的行为。
解决你的问题有两种方法:第一种是使用 new[] 动态分配数组,并返回该指针。使用 new[] 分配的内存永远不会失效,直到你使用 delete[] 释放它。
第二种解决方案是在“调用”函数中定义数组,并将指向它的指针作为参数传递,并让你的函数填充它。
由于我错过了这是一个 C++ 问题,因此有第三个解决方案,我更推荐使用:std::array。然后你可以在函数内部声明数组,并返回对象和编译器将确保根据需要复制数据。

这是一个C++问题,所以不应该真正推荐使用malloc。 - M.M

1
你需要将结果放在堆上,以便它可以在本地函数返回后继续存在:
float* Creature::eulerAngles(const float &q0, const float &q1, const float &q2, const float &q3){

float * angles = new float[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;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接