最有效的是什么?
按值返回。不用担心,不会发生复制。这是最佳做法:
// Use this
vector<float> getResults(int n = 1000);
这是为什么?不会复制从函数返回的局部变量。它们被移到将存储返回值的位置:
// Result moved into v; no copying occurs
vector<float> v = getResults();
// Result moved into memory allocated by new; no copying occurs
vector<float>* q = new vector<float>(getResults());
这是如何工作的?
当函数返回一个对象时,它以两种方式之一返回它:
您只能在寄存器中返回简单对象,例如int
和double
。对于在内存中返回的值,该函数将传递一个指针,该指针指向放置返回值所需的位置。
致电new vector<float>(getResults());
时,会发生以下情况:
- 计算机为新的向量分配内存
- 它将该内存的位置以及任何其他参数提供给
getResults()
。
-
getResults
在该内存中构造向量 ,无需复制。
如何返回对成员变量的引用?
通常来说,这是过早的优化,可能不会提供太多或任何好处,并且它会使您的代码更复杂,更容易错误。
如果将getResults
的输出分配给矢量,则数据将始终被复制:
MyObject m;
vector<float> = m.getResults(); // if getResults returns a const reference,the data gets copied
另一方面,如果将getResults
的输出分配给const reference
,则管理MyObject
的生存期会变得更加复杂。在下面的示例中,由于函数m
被销毁,因此函数返回后,您返回的引用就会失效。
vector<float> const& evilDoNotUseThisFunction() {
MyObject m;
vector<float> const& ref = m.getResults();
return ref; // This is a bug - ref is invalid when m gets destroyed
}
为std::vector
复制和移动有什么区别?
复制遍历向量的所有元素。复制向量时,向量存储的所有数据都将被复制:
vector<float> a = getVector(); // Get some vector
vector<float> b = a // Copies a
这等效于以下代码:
vector<float> a = getVector(); // Get some vector
vector<float> b(a.size()); // Allocate vector of size a
// Copy data; this is O(n)
float* data = b.data();
for(float f : a) {
*data = f;
data++;
}
移动不会在任何元素上循环。由move
构造向量时,就好像它被替换为空向量一样:
vector<float> a = getVector(); // Get some vector
vector<float> b = std::move(a); // Move a into b
等效于:
vector<float> a = getVector(); // Get some vector
vector<float> b; // Make empty vector (no memory allocated)
std::swap(a,b); // Swap a with b; very fast; this is O(1)
TL; DR:复制将循环复制所有数据。移动只是交换出谁拥有内存。
我们怎么知道results
被移动? C ++ 11要求局部变量在返回时自动移动。您不必致电move
。
交换是否确实发生?在许多情况下,不会。交换已经很便宜,但是编译器可以很聪明,可以完全优化交换。通过在要返回{{1的内存中构造您的results
向量}}。这称为命名返回值优化。参见https://shaharmike.com/cpp/rvo/#named-return-value-optimization-nrvo
,
当然这不是最佳的
很好。具体来说,由于使用C ++ 11,因此您无需在此处做任何额外的事情。
无论如何,只有在拥有正确的东西以及分析它的方法之后,您才应该担心优化。
无论如何,返回对私有向量的引用并不理想-它不必要地延长了向量的寿命,并且像其他任何有状态函数一样,稍后可能会导致重新进入问题。
本文链接:https://www.f2er.com/3027327.html