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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/514908/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 15:44:30  来源:igfitidea点击:

Best way to return list of objects in C++?

c++arraysmemory-management

提问by hasen

It's been a while since I programmed in C++, and after coming from python, I feel soooo in a straight Hymanet, ok I'm not gonna rant.

自从我用 C++ 编程以来已经有一段时间了,从 python 转过来后,我觉得穿一件直筒夹克真是太棒了,好吧,我不会咆哮。

I have a couple of functions that act as "pipes", accepting a list as input, returning another list as output (based on the input),

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

this is in concept, but in practice, I'm using std::vectorto represent the list, is that acceptable?

这是概念上的,但实际上,我是std::vector用来表示列表的,这可以接受吗?

further more, I'm not using any pointers, so I'm using std::vector<SomeType> the_list(some_size);as the variable, and returning it directly, i.e. return the_list;

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

P.S. So far it's all ok, the project size is small and this doesn't seem to affect performance, but I still want to get some input/advice on this, because I feel like I'm writing python in C++.

PS 到目前为止一切正常,项目规模很小,这似乎不会影响性能,但我仍然想就此获得一些输入/建议,因为我觉得我正在用 C++ 编写 python。

采纳答案by BigSandwich

The only thing I can see is that your forcing a copy of the list you return. It would be more efficient to do something like:

我唯一能看到的是您强制返回列表的副本。执行以下操作会更有效:

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

Because you pass in the list you want to return, you avoid the extra copy.

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

Edit: This is an old reply. If you can use a modern C++ compiler with move semantics, you don't need to worry about this. Of course, this answer still applies if the object you are returning DOES NOT have move semantics.

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

回答by Pieter

If you really need a new list, I would simply return it. Return value optimization will take care of no needless copies in most cases, and your code stays very clear.
That being said, taking lists and returning other lists is indeed python programming in C++.

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

A, for C++, more suitable paradigm would be to create functions that take a range of iterators and alter the underlying collection.

A,对于 C++,更合适的范式是创建采用一系列迭代器并更改底层集合的函数。

e.g.

例如

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

(with iterator possibly being a template, depending on your needs)

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

Chaining operations is then a matter of calling consecutive methods on begin(), end(). If you don't want to alter the input, you'd make a copy yourself first.

链接操作就是在 begin()、end() 上调用连续方法的问题。如果您不想更改输入,请先自己复制一份。

std::vector theOutput(inputVector);

This all comes from the C++ "don't pay for what you don't need" philosophy, you'd only create copies where you actually want to keep the originals.

这一切都来自 C++“不要为不需要的东西付费”的理念,您只会在真正想要保留原件的地方创建副本。

回答by Ismael

I'd use the generic approach:

我会使用通用方法:

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

Now you can call it

现在你可以调用它

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

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

You can easily change containers used without changing the algorithm used, also it is efficient there's no overhead in returning containers.

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

回答by Schildmeijer

Using a std::vector is the preferably way in many situations. Its guaranteed to use consecutive memory and is therefor pleasant for the L1 cache.

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

You should be aware of what happends when your return type is std::vector. What happens under the hood is that the std::vector is recursive copied, so if SomeType's copy constructor is expensive the "return statement" may be a lengthy and time consuming operation.

你应该知道当你的返回类型是 std::vector 时会发生什么。在幕后发生的事情是 std::vector 是递归复制的,因此如果 SomeType 的复制构造函数很昂贵,则“返回语句”可能是一个冗长且耗时的操作。

If you are searching and inserting a lot in your list you could look at std::set to get logarithmic time complexity instead of linear. (std::vectors insert is constant until its capacity is exceeded).

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

You are saying that you have many "pipe functions"... sounds like an excellent scenario for std::transform.

你是说你有很多“管道函数”......听起来像是 std::transform 的一个很好的场景。

回答by Robert Gould

If you want to be really hardcore, you could use boost::tuple.

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

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

But since it seems all your objects are of a single, non-polymorphic type, then the std::vector is all well and fine. If your types were polymorphic (inherited classes of a base class) then you'd need a vector of pointers, and you'd need to remember to delete all the allocated objects before throwing away your vector.

但是,由于您的所有对象似乎都是单一的非多态类型,因此 std::vector 一切正常。如果您的类型是多态的(基类的继承类),那么您需要一个指针向量,并且您需要记住在丢弃向量之前删除所有分配的对象。

回答by heeen

Another problem with returning a list of objects (opposed to working on one or two lists in place, as BigSandwich pointed out), is if your objects have complex copy constructors, those will called for each element in the container.

返回对象列表的另一个问题(与 BigSandwich 指出的在适当位置处理一两个列表相反)是,如果您的对象具有复杂的复制构造函数,那么这些构造函数将针对容器中的每个元素调用。

If you have 1000 objects each referencing a hunk of memory, and they copy that memory on Object a, b; a=b; that's 1000 memcopys for you, just for returning them contained in a container. If you still want to return a container directly, think about pointers in this case.

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

回答by heeen

It works very simple.

它的工作非常简单。

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

Now receiving data:

现在接收数据:

list<int> lst=foo();

Is fully optimal because compiler know to optimize constructor of lst well. and would not cause copies.

是完全最优的,因为编译器知道如何优化 lst 的构造函数。并且不会造成副本。

Other method, more portable:

其他方法,更便携:

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

What happens: foo already optimized so there is no problem to return the value. When you call swap you set value of lst to new, and thus do not copy it. Now old value of lst is "swapped" and destructed.

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

This is the efficient way to do the job.

这是完成工作的有效方法。