0

我来自 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 仍然存在于范围之外?容器中的每次插入是否也意味着复制?

4

2 回答 2

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 建议的那样,即使没有这样做,返回值优化也应该优化掉副本。

新 C++ (c++11) -只要不再使用输入变量,
使用构造列表会比复制更有效。emplace_back(感谢@特洛伊)

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

于 2013-01-14T02:34:29.027 回答
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 也有类似的特性。如此有效地,您的代码比使用参数返回值更具可读性,是正确的方法,并且如果您使用最新的编译器,应该可以很好地工作。

于 2013-01-14T02:59:22.703 回答