当您从函数返回 stl 向量时:
vector<int> getLargeArray() { ... }
返回将是一个昂贵的复制操作吗?我记得在某处读到向量分配很快——我是否应该要求调用者传递引用?
void getLargeArray( vector<int>& vec ) { ... }
假设你的函数构造并返回新数据,你应该按值返回,并尝试确保函数本身有一个返回点,该返回点返回一种类型的变量vector<int>
,或者最坏的情况是几个返回点都返回相同的变量。
这确保您将在任何可靠的编译器上获得指定的返回值优化,从而消除one潜在副本(从函数中的值到返回值的副本)。还有其他方法可以实现返回值优化,但它并不完全可预测,因此简单的规则是安全的。
接下来,您希望消除从返回值到调用者对其执行的任何操作的潜在副本。这是调用者要解决的问题,而不是被调用者的问题,基本上有三种方法可以做到这一点:
- 使用对函数的调用作为初始化程序
vector<int>
,在这种情况下,任何可靠的 C++ 编译器都会删除该副本。
- 使用 C++11,其中
vector
具有移动语义。
- 在 C++03 中,使用“交换优化”。
也就是说,在C++03中don't write
vector<int> v;
// use v for some stuff
// ...
// now I want fresh data in v:
v = getLargeArray();
Instead:
getLargeArray().swap(v);
这避免了所需的复制分配(不得省略[*])v = getLargeArray()
。在 C++11 中不需要它,其中有一个便宜的移动分配而不是昂贵的复制分配,但当然它仍然有效。
另一件需要考虑的事情是你是否真的想要vector
作为界面的一部分。您可以改为编写一个函数模板,该模板采用输出迭代器,并将数据写入该输出迭代器。想要向量中的数据的调用者可以传入以下结果std::back_inserter
,因此想要数据的调用者也可以deque
or list
。提前知道数据大小的调用者甚至可以只传递一个向量迭代器(适当地resize()
d 首先)或指向足够大数组的原始指针,以避免开销back_insert_iterator
。有一些非模板方法可以做同样的事情,但它们很可能会以某种方式产生调用开销。如果您担心复制的成本int
每个元素,那么您就会担心每个元素的函数调用的成本。
如果您的函数不构造并返回新数据,而是返回某些现有数据的当前内容vector<int>
并且不允许更改原件,那么当您按值返回时,您将无法避免至少一份副本。因此,如果其性能已被证实存在问题,那么您需要查看除按值返回之外的其他 API。例如,您可以提供一对可用于遍历内部数据的迭代器、一个通过索引在向量中查找值的函数,甚至(如果性能问题严重到需要暴露您的内部),对向量的引用。显然,在所有这些情况下,您都会更改函数的含义 - 现在不再为调用者提供“他们自己的数据”,而是提供其他人的数据的视图,这些数据可能会发生变化。
[*] 当然,“好像”规则仍然适用,并且人们可以想象一种 C++ 实现,它足够聪明,能够意识到这一点,因为这是一个普通可复制类型的向量 (int
),并且由于您没有获取任何指向任何元素的指针(我假设),因此它可以进行交换,并且结果“就像”它复制了一样。但我不会指望它。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)