C++ 在函数中填充容器避免分段错误

C++ 在函数中填充容器避免分段错误,c++,stl,scope,segmentation-fault,C++,Stl,Scope,Segmentation Fault,我来自Java,在那里填充容器不需要思考。我现在使用C++的问题是,在函数中填充一个容器,其中函数在函数作用域中声明的数据会导致错误,当我想访问数据时,数据不再存在。 我找不到解决这个问题的教程,所以我采用Java的方式,只让容器中的指针声明为“new”。但现在我不得不退一步 std::list<Vertex<float> > std::list 从一个函数开始,我想这可能是学习如何填充和返回这样的东西的一个好点。会这样吗 { std::list<Vertex&

我来自Java,在那里填充容器不需要思考。我现在使用C++的问题是,在函数中填充一个容器,其中函数在函数作用域中声明的数据会导致错误,当我想访问数据时,数据不再存在。 我找不到解决这个问题的教程,所以我采用Java的方式,只让容器中的指针声明为“new”。但现在我不得不退一步

std::list<Vertex<float> >
std::list
从一个函数开始,我想这可能是学习如何填充和返回这样的东西的一个好点。会这样吗

{
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;
}
{
std::列表myList;
顶点v(0.0,0.1,0.2);
我的列表。推回(v);
myList.push_back(顶点(1,0,1.1,1.2));
返回myList;
}
作为一个示例函数体,实际上可以吗?如果是,为什么v仍然存在于范围之外?容器中的每次插入是否也意味着复制?

这将“很好”,因为每个操作都会创建一个副本

  • myList.push_back(v)
    创建
    v
    的副本,这样
    v
    的可见性现在就不相关了
  • 返回myList
    将列表的副本返回给调用函数,因此myList的可见性现在与此无关。调用函数应复制此列表以将其保留在范围内,否则它将在调用此函数的行的执行结束时被销毁
引用fine的原因是拷贝通常很昂贵。在您的情况下,它们非常小,因此可能无关紧要,在许多情况下,它们可能会被优化掉,但仍然需要记住

<强>旧C++方式优化是通过引用传递列表,并使用该列表来构造列表,而不是按值返回。

void MakeMeAList(std::list<Vertex<float> >& aList){
    ....
}

std::list<Vertex<float> > aList;
MakeMeAList(aList);
void MakeMeAList(标准::列表和列表){
....
}
列表列表;
制作列表(MakeMeAList);
正如@billz所建议的,即使不这样做,我们也应该优化掉拷贝

<强>新C++(C++ 11)-< /强> BR> 只要不再使用输入变量,使用

emplace\u back
构建列表将比复制更有效。(谢谢@Troy)


我的C++11很弱,我几乎可以肯定,即使按值返回也没问题,因为移动语义会优化它,但我只有95%的把握。

要补充Karthik的回答,如果您使用的是实现r值引用(C++0x标准的一部分)的相对较新的编译器,您的方法将非常有效,不会受到复制操作的负面影响

退房 对于r值的简要介绍

请注意,在采用r值引用之前,许多编译器通过所谓的返回值优化消除了返回集合所涉及的“昂贵的复制操作”。Wiki还有更多细节:


VisualStudio2005(及更新版本)实现了RVO,我相信GCC也有类似的特性。因此,实际上,您的代码比使用参数返回值更具可读性,这是正确的方法,如果您使用的是最新的编译器,它应该工作得很好。

是的。“向后推”会创建插入对象的副本。c++11中的emplace_提供了就地构造,而不是复制。v将不存在于函数之外。但是change v不会改变myList中的值。在C++11中,我认为在移动到myList之后您不能访问v。除了一个小细节之外,这很好:您几乎肯定不想使用
std::list
(虽然它可能很有用,但却相当少见)。在这些情况下,我如何避免复制?指针,再次?@ArneRecknagel您可以通过将列表作为引用传递来避免返回列表,并且可以通过使用@Troy建议的
emplace\u back
来避免处理向量