这是一个奇怪的行为,我不明白我有。
我有一个带有列表的a类,上面有一个getter:
class A
{
private:
std::list<OtherClass *> l;
public:
std::list<OtherClass *> getL()
{
return l;
}
}然后,如果我这样做:
A inst;
std::list<OtherClass *>::iterator itB = inst.getL().begin();
std::list<OtherClass *>::iterator itE = inst.getL().end();
for (; itB != itE; ++itB) // Instant ABORT !但如果我这么做了:
A inst;
std::list<OtherClass *> l = inst.getL();
std::list<OtherClass *>::iterator itB = l.begin();
std::list<OtherClass *>::iterator itE = l.end();
for (; itB != itE; ++itB) // It works now !有人能给我解释一下为什么会这样吗?为什么我必须经历像这样的临时变量才不会中止呢?提前谢谢你!
发布于 2013-01-20 07:46:11
到目前为止,所有的答案都告诉你如何正确地做这件事,但我想我应该给你一些为什么你的代码不能工作的更多细节。因此,正如其他人所指出的,您的"getter“是按值返回列表。这是(主要)C++特有的东西:作为程序员,您必须显式地指定是通过值传递对象还是通过引用传递对象。其他编程语言,如Java,将(几乎)总是通过引用传递。假设您像这样分配了一个变量:
MyClass a;
MyClass b = a;在许多语言中,赋值的意思是:使b成为指向a的引用。然后,您将能够调用b上的方法,并且它的行为就像是a一样。
另一方面,在C++中,这意味着:“创建第二个对象b,然后将a的所有状态复制到b中(忽略MyClass具有复制构造函数的可能性,这与此解释无关)。现在对于列表,这意味着每个元素都将被复制到新创建的列表中!(除了其他影响,这可能是一个性能问题)。”
另一方面,如果您告诉编译器引用一个:
MyClass& b = a;那么这个b的行为就好像它是一个。不会复制任何状态,并且更改b将更改a。
好了,现在回到你的代码示例。在第一个版本中,您具有以下行:
// Creates an invalid iterator!
std::list<OtherClass *>::iterator itB = inst.getL().begin();这实际上是一堆不同的东西。对inst.getL()的调用将创建一个新的列表,并将inst的列表成员的所有内容复制到其中。然后,它将获得该副本的迭代器。之后,副本本身将被销毁,迭代器将变得无效。为什么?因为您没有将列表的副本分配给任何对象。在C++中,超出作用域的堆栈分配对象(即不是使用new创建的对象)将被析构。简单地说,当对象不能再通过其名称访问时,就会发生“超出作用域”:
{ // Begin scope
MyClass o;
// Inside the braces, it's possible to refer to o:
o.doSomething();
} // End scope
o.doSomething() // Will be an error, as o is not "known" anymore如果丢弃函数的返回值,也会发生这种情况,比如这样写:
inst.getL(); 这将创建一个列表的副本,然后再次销毁它。
现在,为什么你的第二个例子是可行的?因为您将列表的副本分配给tempory变量,所以它们留在作用域中:
std::list<OtherClass *> l = inst.getL();来自"getter“调用的临时对象被存储到l中(暂时忽略赋值操作符、RVO等),并且为l获得的所有迭代器现在都将有效,直到l超出作用域。
std::list<OtherClass *>::iterator itB = l.begin(); // valid因此,这是可行的,尽管可能与您预期的不同:迭代器是在列表的副本上操作,而不是在实际数据上操作。这有时可能是你想要的--但在你的情况下,你想要其他答案所建议的参考。
希望这篇文章能帮你弄清楚一点。
https://stackoverflow.com/questions/14419944
复制相似问题