【发布时间】:2015-08-30 17:53:51
【问题描述】:
假设我有这个非常简单的代码:
std::vector<int> getVector( int size )
{
std::vector<int> res;
for ( size_t i = 0; i != size; ++i )
res.push_back( i* 23 );
return res;
}
int main ()
{
std::vector<int> v;
v = getVector(10);
std::cout << "Size1 is " << v.size() << std::endl;
v = getVector(15);
std::cout << "Size2 is " << v.size() << std::endl;
}
它输出:
Size1 为 10
Size2 为 15
现在,假设我想更改getVector 以避免无用的对象复制并优化速度和内存使用。所以getVector 现在将获得对要填充的向量的引用。
void getVector( int size, std::vector<int>& res )
{
for ( size_t i = 0; i != size; ++i )
res.push_back( i* 23 );
}
现在,如果我改变主函数,不注意:
int main ()
{
std::vector<int> v;
getVector(10,v);
std::cout << "Size1 is " << v.size() << std::endl;
getVector(15,v);
std::cout << "Size2 is " << v.size() << std::endl;
}
它输出:
Size1 为 10
Size2 为 25
这不是我最初拥有的。
我已经多次进行这种更改(用引用传递的对象替换返回值),而且我一直在问自己同样的问题:谁应该清除向量?
是否有任何“指导方针”或“一般规则”说明在这种情况下谁应该清除向量?
函数本身应该做吗?
void getVector( int size, std::vector<int>& res )
{
res.clear();
for ( size_t i = 0; i != size; ++i )
res.push_back( i* 23 );
}
或者调用者应该这样做?
int main ()
{
std::vector<int> v;
getVector(10,v);
std::cout << "Size1 is " << v.size() << std::endl;
v.clear();
getVector(15,v);
std::cout << "Size2 is " << v.size() << std::endl;
}
编辑:
正如许多人所报告的那样,示例可能是错误的,因为它是“糟糕的优化”。但是可能存在通过引用检索向量并且问题仍然存在的情况。例如:
bool hasData( std::vector<int>& retrievedData );
或
void splitVector( const std::vector<int>& originalVector,
std::vector<int>& part1,
std::vector<int>& part2 );
...
【问题讨论】:
-
没有“唯一正确的方法”。这是在这种特定情况下最有意义的事情。这实际上取决于您传递引用而不是返回值的原因,您只会出于某些不寻常的原因这样做。
-
“现在,假设我想更改 getVector 以避免无用的对象复制并优化速度和内存使用。”。你知道,矢量是可移动的。
-
如果函数的功能表现为从一个空向量开始,那么函数应该清除它
-
还请注意,如果您在 C++11 中,由于移动语义,按值返回只是指针的交换。此外,您的案例中还有 RVO 和 NRVO。
-
您甚至必须询问谁应该清除向量这一事实很好地暗示了当您可以按值返回时接受引用是一种反模式。
标签: c++ vector pass-by-reference