简单的代码,看似随机的结果 - 这是由于过时的引用吗?
Posted
技术标签:
【中文标题】简单的代码,看似随机的结果 - 这是由于过时的引用吗?【英文标题】:simple code, seemingly random result - is this due to a stale reference? 【发布时间】:2016-04-08 01:41:02 【问题描述】:下面的代码涉及一个由 int 向量组成的向量,它由一个带有两个元素的向量组成。该代码非常不言自明。我希望每个打印语句的输出为 2,但第二个打印语句打印 6。
我猜这与引用的传递和事物的构造顺序有关,但我无法解释。你能解释一下这个输出吗?我究竟做错了什么?
谢谢,
丹
#include <vector>
#include <iostream>
#include <cassert>
using namespace std;
class Permutation
public:
Permutation(const vector<vector<int> >& cycles) : _cycles(cycles)
static Permutation foo()
vector<vector<int> > cycles = 2,3;
assert(cycles.front().size() == 2); // foo seems to create the correct thing locally
return Permutation(cycles);
const vector<vector<int> >& _cycles;
;
int main()
vector<vector<int> > cycles = 2,3;
Permutation perm(cycles);
cout << perm._cycles.front().size() << endl; // outputs 2, as expected
cout << Permutation::foo()._cycles.front().size() << endl; // outputs 6, seems like garbage to me
return 0;
【问题讨论】:
_cycles
在foo
中持有对cycles
的引用,一旦foo
返回,该引用就失效了。
【参考方案1】:
您的猜测大部分是正确的。并不是引用的传递是个问题,而是在所有的引用都被到处传递之后,被引用的对象超出了范围并被销毁了,而引用仍然悬而未决。在那个时候使用引用变成了未定义的行为。
当一切都说完了,_cycles
最终成为来自已返回函数的函数范围对象的引用,从而破坏了被引用的对象。您所做操作的简化示例:
int &foo()
int bar=4;
return bar;
void foobar()
int &blah=foo();
foo()
返回了一个函数范围对象的引用,该对象在foo()
返回时已经被销毁,因此返回的引用是指一个超出范围并被销毁的对象。使用引用现在是未定义的行为。
【讨论】:
【参考方案2】:在 foo() 中,您在当前堆栈帧中分配一个 Permutation 对象,然后返回给调用者,销毁该帧(即超出范围)。相反,您可以在堆上分配新的 Permutation 对象并返回指针,请记住,如果在除立即退出的示例之外的其他操作中完成,您将希望在某个时候释放它。
#include <vector>
#include <iostream>
#include <cassert>
using namespace std;
class Permutation
public:
Permutation(const vector<vector<int> >& cycles) : _cycles(cycles)
static Permutation * foo()
vector<vector<int> > cycles = 2,3;
assert(cycles.front().size() == 2); // foo seems to create the correct thing locally
return new Permutation(cycles);
const vector<vector<int> >& _cycles;
;
int main()
vector<vector<int> > cycles = 2,3;
Permutation perm(cycles);
cout << perm._cycles.front().size() << endl; // outputs 2, as expected
cout << Permutation::foo()->_cycles.front().size() << endl; // outputs 6, seems like garbage to me
return 0;
【讨论】:
【参考方案3】:我换行了:
常量向量>& _cycles;
到
常量向量> _cycles;
一切正常!
【讨论】:
那是因为,您的代码现在不再包含对可能被销毁的对象的引用,而是包含该对象的副本,该副本将在原始对象被销毁后继续存在(并链接到生命周期Permutations
对象)。如果您不明白为什么会这样,请避免使用作为引用的类/结构成员。以上是关于简单的代码,看似随机的结果 - 这是由于过时的引用吗?的主要内容,如果未能解决你的问题,请参考以下文章