未定义的行为

Undefined behaviour

我正在用 C++ 进行一些模拟,我遇到了一个奇怪的问题。我有以下函数,其中 return 是一个双精度向量:

vector<double> processSimulation(int Q){
//do things
vector<double> output;
output.push_back(mean);
output.push_back(variance);
return output;
}

我主要有以下几点:

//define Q
vector<double>::iterator it = processSimulation(Q).begin();
double mean = *it;
double variance = *(it+1);

问题是我得到了一个错误的均值数字(e-305)和一个正确的方差数字。 我试图自己解释这种行为,我认为这可能是由未定义的行为引起的,因为迭代器指向函数中的旧向量,它现在超出范围并且存在不再。我对么? 也许我很幸运方差是正确的,因为它也可能是错误的。

我把代码改成了

vector<double> output = processSimulation(Q);
vector<double>::iterator it = output.begin();
//same as before

它工作得很好,所以这加强了我的假设。

我还注意到 调试器的怪异之处:在试图弄清楚发生了什么时(在修复代码之前),我通过调试查看了均值和方差的值,它们都错了。虽然,当我运行程序时,只有均值是错误的(我已经尝试了很多次,但总是这样:调试时均错,均值错误且方差正确,而 运行)。 这里发生了什么?

Java问题:好吧,我遇到的这个问题真的很困扰我,因为经常在Java,为了缩短事情,我没有' 定义新对象,但直接在 return 该对象的函数上使用方法(如本例所示)。虽然,我从来没有遇到过任何问题。我是否总是不经意地(幸运地)做事?或者只是 在 Java 中不存在这样的行为 ,因为应该 return 对象的函数实际上是 return 指向它们的指针和真实的对象总是在堆中(并且在没有引用它们时被丢弃)?

希望你能解开我的疑惑!

这是一个非常常见的错误,当人们懒于对 rvalues 进行链接调用而不是将结果存储在局部变量中时。

vector<double>::iterator it = processSimulation(Q).begin();

在上面,您的 processSimulation(Q) 调用 returns vector<double>。然后,您获得指向向量开头的迭代器并将其存储。现在生成的向量不再在范围内,它被销毁了。这留下了一个悬空的迭代器。

现在您可以开始使用它了。请记住,该迭代器包含有效信息,但它指向一个不再存在的对象:

double mean = *it;            // undefined behaviour
double variance = *(it+1);    // undefined behaviour

想起来有点像这样:

vector<double>::iterator it;
{
    vector<double> result = processSimulation(Q);
    it = result.begin();
}
double mean = *it;    // boom

当您更改代码以将 return 值存储在局部变量中时,行为将被定义,前提是向量在您使用迭代器的整个过程中都保持在范围内。

所以这是正确的(除了 C++ style-related 对你的问题的评论):

vector<double> output = processSimulation(Q);
vector<double>::iterator it = output.begin();
double mean = *it;
double variance = *(it+1);

但是您可以轻松地放弃迭代器并使用数组索引运算符:

double mean = output[0];
double variance = output[1];

您可能需要考虑 return 使用自己的结构来封装此信息,而不是向量。或者至少切换到使用 std::pair<double, double>.