我用C ++编程已经有一段时间了,来自python之后,我穿着直筒夹克感觉太棒了,好吧,我不会咆哮。
我有几个函数充当“管道”,接受列表作为输入,返回另一个列表作为输出(基于输入),
这是概念性的,但在实践中,我使用std::vector
来表示列表,是否可以接受?
此外,我没有使用任何指针,所以我使用std::vector<SomeType> the_list(some_size);
作为变量,并直接返回它,即return the_list;
P.S。到目前为止一切都还好,项目大小很小,这似乎不会影响性能,但我仍然希望得到一些输入/建议,因为我觉得我在用C ++编写python。
答案 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被“交换”并被破坏。
这是完成这项工作的有效方式。