如何 return 方法体中声明的向量的引用?
How to return the reference of a declared vector in the method body?
我有这个方法:
vector<float> MyObject::getResults(int n = 1000)
{
vector<float> results(n, 0);
// do some stuff
return results;
}
当然这没有优化,我想 return 这个向量的参考,但我不能简单地这样做 :
const vector<float>& MyObject::getResults(int n = 1000)
{
vector<float> results(n, 0);
// do some stuff
return results;
}
这不起作用,向量将在方法结束时销毁,因为它是局部变量。
所以我发现解决这个问题的唯一方法是在 MyObject 中创建一个私有向量并 return 对此向量的引用:
const vector<float>& MyObject::getResults(int n = 1000)
{
this->results.clear();
this->results.resize(n, 0);
// do some stuff
return results;
}
这样做正确吗?您还有其他解决方案吗?
什么最有效?
Return 按值。别担心,不会发生复制。 这是最佳做法:
// Use this
vector<float> getResults(int n = 1000);
这是为什么? 从函数 编辑的局部变量 return 未被复制 。它们被移动到将存储 return 值的位置:
// 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());
这是如何工作的?
当一个函数 return 是一个对象时,它 return 以两种方式之一来实现它:
- 在寄存器中
- 记忆中
您只能在寄存器中 return 简单对象,例如 int
和 double
。对于内存中的 returned 值,函数将传递一个指向它需要放置 return 值的位置的指针。
当您调用 new vector<float>(getResults());
时,会发生以下情况:
- 计算机为新向量分配内存
- 它将内存的位置连同任何其他参数一起提供给
getResults()
。
getResults
在那个内存中构造向量,不需要复制。
如何return引用成员变量?
一般来说,这是一个过早的优化,可能不会提供太多或任何好处,并且它使您的代码更复杂,更容易出现错误。
如果您将 getResults
的输出分配给向量,那么数据无论如何都会被复制:
MyObject m;
vector<float> = m.getResults(); // if getResults returns a const reference, the data gets copied
另一方面,如果将 getResults
的输出分配给 const reference
,这会使 MyObject
的生命周期管理变得更加复杂。在下面的示例中,您 return 的引用在函数结束后立即失效 因为 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 要求局部变量 自动 当它们被移动时已 returned。您不必致电 move
.
交换真的发生了吗?在很多情况下,没有。交换已经很便宜了,但是 编译器可以聪明地完全优化掉交换。 它通过在内存中构建 results
向量来做到这一点 returning results
。这称为命名 Return 值优化。参见 https://shaharmike.com/cpp/rvo/#named-return-value-optimization-nrvo
Of course this is not optimized
没关系。具体来说,自 C++11 起,您无需在此处执行任何额外操作。
在任何情况下,只有当您拥有正确的东西并找到分析它的方法后,您才应该担心优化。
无论如何,返回对私有 vector 的引用并不理想 - 它不必要地延长了 vector 的生命周期,并且可能会在以后导致重入问题,就像任何其他有状态函数一样。
我有这个方法:
vector<float> MyObject::getResults(int n = 1000)
{
vector<float> results(n, 0);
// do some stuff
return results;
}
当然这没有优化,我想 return 这个向量的参考,但我不能简单地这样做 :
const vector<float>& MyObject::getResults(int n = 1000)
{
vector<float> results(n, 0);
// do some stuff
return results;
}
这不起作用,向量将在方法结束时销毁,因为它是局部变量。
所以我发现解决这个问题的唯一方法是在 MyObject 中创建一个私有向量并 return 对此向量的引用:
const vector<float>& MyObject::getResults(int n = 1000)
{
this->results.clear();
this->results.resize(n, 0);
// do some stuff
return results;
}
这样做正确吗?您还有其他解决方案吗?
什么最有效?
Return 按值。别担心,不会发生复制。 这是最佳做法:
// Use this
vector<float> getResults(int n = 1000);
这是为什么? 从函数 编辑的局部变量 return 未被复制 。它们被移动到将存储 return 值的位置:
// 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());
这是如何工作的?
当一个函数 return 是一个对象时,它 return 以两种方式之一来实现它:
- 在寄存器中
- 记忆中
您只能在寄存器中 return 简单对象,例如 int
和 double
。对于内存中的 returned 值,函数将传递一个指向它需要放置 return 值的位置的指针。
当您调用 new vector<float>(getResults());
时,会发生以下情况:
- 计算机为新向量分配内存
- 它将内存的位置连同任何其他参数一起提供给
getResults()
。 getResults
在那个内存中构造向量,不需要复制。
如何return引用成员变量?
一般来说,这是一个过早的优化,可能不会提供太多或任何好处,并且它使您的代码更复杂,更容易出现错误。
如果您将 getResults
的输出分配给向量,那么数据无论如何都会被复制:
MyObject m;
vector<float> = m.getResults(); // if getResults returns a const reference, the data gets copied
另一方面,如果将 getResults
的输出分配给 const reference
,这会使 MyObject
的生命周期管理变得更加复杂。在下面的示例中,您 return 的引用在函数结束后立即失效 因为 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 要求局部变量 自动 当它们被移动时已 returned。您不必致电 move
.
交换真的发生了吗?在很多情况下,没有。交换已经很便宜了,但是 编译器可以聪明地完全优化掉交换。 它通过在内存中构建 results
向量来做到这一点 returning results
。这称为命名 Return 值优化。参见 https://shaharmike.com/cpp/rvo/#named-return-value-optimization-nrvo
Of course this is not optimized
没关系。具体来说,自 C++11 起,您无需在此处执行任何额外操作。
在任何情况下,只有当您拥有正确的东西并找到分析它的方法后,您才应该担心优化。
无论如何,返回对私有 vector 的引用并不理想 - 它不必要地延长了 vector 的生命周期,并且可能会在以后导致重入问题,就像任何其他有状态函数一样。