在C ++中返回对象列表的最佳方法?

时间:2009-02-05 07:24:59

标签: c++ arrays memory-management

我用C ++编程已经有一段时间了,来自python之后,我穿着直筒夹克感觉太棒了,好吧,我不会咆哮。

我有几个函数充当“管道”,接受列表作为输入,返回另一个列表作为输出(基于输入),

这是概念性的,但在实践中,我使用std::vector来表示列表,是否可以接受?

此外,我没有使用任何指针,所以我使用std::vector<SomeType> the_list(some_size);作为变量,并直接返回它,即return the_list;

P.S。到目前为止一切都还好,项目大小很小,这似乎不会影响性能,但我仍然希望得到一些输入/建议,因为我觉得我在用C ++编写python。

7 个答案:

答案 0 :(得分:16)

我唯一能看到的是你强制复制你返回的列表。做以下事情会更有效:

  void DoSomething(const std::vector<SomeType>& in, std::vector<SomeType>& out)
  {
  ...
  // no need to return anything, just modify out
  }

因为您传入了要返回的列表,所以可以避免使用额外的副本。

编辑:这是一个旧回复。如果您可以使用带有移动语义的现代C ++编译器,则无需担心这一点。当然,如果你要返回的对象没有移动语义,这个答案仍然适用。

答案 1 :(得分:13)

如果你真的需要一个新的清单,我会简单地归还它。在大多数情况下,返回值优化将不会处理任何不必要的副本,并且您的代码保持清晰。
话虽如此,获取列表并返回其他列表确实是C ++中的python编程。

对于C ++,更合适的范例是创建带有一系列迭代器并改变底层集合的函数。

e.g。

void DoSomething(iterator const & from, iterator const & to);

(根据您的需要,迭代器可能是模板)

链接操作是在begin(),end()上调用连续方法的问题。 如果你不想改变输入,你首先要自己复制。

std::vector theOutput(inputVector);

这一切都来自C ++“不为你不需要的东西买单”的理念,你只需创建你想要保留原件的副本。

答案 2 :(得分:4)

我会使用通用方法:

template <typename InIt, typename OutIt>
void DoMagic(InIt first, InIt last, OutIt out)
{
  for(; first != last; ++first) {
    if(IsCorrectIngredient(*first)) {
      *out = DoMoreMagic(*first);
      ++out;
    }
  }
}

现在你可以称之为

std::vector<MagicIngredients> ingredients;
std::vector<MagicResults> result;

DoMagic(ingredients.begin(), ingredients.end(), std::back_inserter(results));

您可以轻松更改所使用的容器而无需更改所使用的算法,而且返回容器也没有任何开销。

答案 3 :(得分:1)

如果你想成为真正的铁杆,你可以使用boost::tuple

tuple<int, int, double> add_multiply_divide(int a, int b) {
  return make_tuple(a+b, a*b, double(a)/double(b));
}

但是因为看起来你的所有对象都是单一的非多态类型,所以std :: vector一切都很好。 如果您的类型是多态的(基类的继承类),那么您需要一个指针向量,并且您需要记住在丢弃向量之前删除所有已分配的对象。

答案 4 :(得分:1)

在许多情况下,使用std :: vector是最好的方法。它保证使用连续的内存,因此对于L1缓存来说是愉快的。

当你的返回类型是std :: vector时,你应该知道发生了什么。引擎盖下发生的事情是std :: vector被递归复制,因此如果SomeType的复制构造函数很昂贵,那么“return语句”可能是一个漫长而耗时的操作。

如果您在列表中搜索并插入很多内容,可以查看std :: set以获得对数时间复杂度而不是线性。 (std :: vectors insert是不变的,直到超过其容量)。

你说你有很多“管道功能”......听起来像是std :: transform的绝佳场景。

答案 5 :(得分:0)

返回一个对象列表的另一个问题(与BigSandwich所指出的一个或两个列表相反)是,如果你的对象有复杂的复制构造函数,那些将调用容器中的每个元素。

如果你有1000个对象,每个对象都引用了一大块内存,并且它们将这个内存复制到对象a,b; A = B;这是你的1000份memcopys,只是为了将它们包含在容器中。如果您仍想直接返回容器,请考虑这种情况下的指针。

答案 6 :(得分:0)

它非常简单。

list<int> foo(void)
{
    list<int> l; 
    // do something
    return l;
}

现在接收数据:

list<int> lst=foo();

完全最优,因为编译器知道优化lst的构造函数。和 不会导致副本。

其他方法,更便携:

list<int> lst;
// do anything you want with list
lst.swap(foo());

会发生什么:foo已经优化,因此返回值没有问题。什么时候 你调用swap你将lst的值设置为new,因此不要复制它。现在旧的价值 lst被“交换”并被破坏。

这是完成这项工作的有效方式。