我来自Java,填充容器不涉及思考。现在我使用c ++的问题是,在函数填充函数中的容器填充函数范围内的数据会导致错误,当我想访问它时数据不再存在。 我找不到解决问题的教程,所以我采用Java方式,只使容器获得用“new”声明的指针。但现在我被迫返回
std::list<Vertex<float> >
从一个函数和思想这可能是一个很好的点,以了解我将如何填充和返回这样的事情。会这样吗
{
std::list<Vertex<float> > myList;
Vertex<float> v(0.0, 0.1, 0.2);
myList.push_back(v);
myList.push_back(Vertex<float>(1,0, 1.1, 1.2));
return myList;
}
实际上作为样本函数体很好吗?如果是的话,为什么v仍然存在于范围之外?容器中的每个插入是否也意味着复制?
答案 0 :(得分:1)
这样可以“正常”,因为那里的每个操作都会创建一个副本。
myList.push_back(v);
会创建v
的副本,以便v
的可见性现在无关紧要。 return myList;
将列表的副本返回给调用函数,因此myList的可见性现在无关紧要。调用函数应该复制此列表以使其保持在范围内,否则它将在执行调用此函数的行的末尾被销毁。引用罚款的原因是副本通常很昂贵。在你的情况下它们很小,所以它可能是无关紧要的,并且在许多情况下它们可能会被优化掉,但它仍然需要牢记。
优化的旧C ++方式是通过引用传递列表并使用它来构建列表,而不是按值返回。
void MakeMeAList(std::list<Vertex<float> >& aList){
....
}
std::list<Vertex<float> > aList;
MakeMeAList(aList);
正如@billz建议的那样,Return Value Optimization应该优化副本,即使没有这样做。
新C ++(c ++ 11) -
只要输入变量不再被使用,使用emplace_back
来构造列表将比复制更有效。 (感谢@Troy)
我的C ++ 11很弱,我几乎可以肯定即使按值返回也行,因为Move语义会优化它,但我只有95%肯定。
答案 1 :(得分:1)
要添加Karthik的回复,如果您使用的是一个相对较新的编译器来实现r值引用(C ++ 0x标准的一部分),那么您的方法将完美地工作,而不会产生复制操作的负面影响。
结帐http://en.wikipedia.org/wiki/C%2B%2B11#Rvalue_references_and_move_constructors 简要介绍一下r值。
请注意,在采用r值引用之前,许多编译器通过所谓的返回值优化消除了返回集合所涉及的“昂贵的复制操作”。 Wiki再次提供了更多细节: http://en.wikipedia.org/wiki/Return_value_optimization
Visual Studio 2005(及更新版本)实现了RVO,我相信GCC也有类似的功能。如此有效地,您的代码比使用参数返回值更具可读性,这是正确的方法,如果您使用的是最新的编译器,它应该能够很好地工作。