在函数中返回std :: vector时复制了多少数据,将std :: vector放在free-store(在堆上)并返回指针即是多大的优化即是:
std::vector *f()
{
std::vector *result = new std::vector();
/*
Insert elements into result
*/
return result;
}
比以下更有效率:
std::vector f()
{
std::vector result;
/*
Insert elements into result
*/
return result;
}
答案 0 :(得分:67)
在C ++ 11中,这是首选方式:
std::vector<X> f();
即,按价值返回。
使用C ++ 11,std::vector
具有移动语义,这意味着在函数中声明的 local 向量将在返回时被移动甚至移动也可以由编译器省略。
答案 1 :(得分:36)
你应该按价值回归。
该标准具有提高按价值返回效率的特定功能。它被称为“复制省略”,更具体地说就是“命名返回值优化(NRVO)”。
编译器不必实现它,但是编译器再次 来实现函数内联(或者根本不执行任何优化)。但是,如果编译器没有优化,标准库的性能可能会非常差,并且所有严格的编译器都实现了内联和NRVO(以及其他优化)。
当应用NRVO时,以下代码中将不会复制:
std::vector<int> f() {
std::vector<int> result;
... populate the vector ...
return result;
}
std::vector<int> myvec = f();
但是用户可能想要这样做:
std::vector<int> myvec;
... some time later ...
myvec = f();
复制elision不会阻止复制,因为它是一个赋值而不是初始化。但是,您应该仍按值返回。在C ++ 11中,赋值通过不同的东西进行优化,称为“移动语义”。在C ++ 03中,上面的代码确实会产生副本,虽然理论上 但优化器可能能够避免它,但实际上它太难了。因此,在C ++ 03中你应该写下这个代替myvec = f()
而不是{/ p>
std::vector<int> myvec;
... some time later ...
f().swap(myvec);
还有另一种选择,即为用户提供更灵活的界面:
template <typename OutputIterator> void f(OutputIterator it) {
... write elements to the iterator like this ...
*it++ = 0;
*it++ = 1;
}
您可以在此基础上支持现有的基于矢量的界面:
std::vector<int> f() {
std::vector<int> result;
f(std::back_inserter(result));
return result;
}
如果您的现有代码使用reserve()
的方式比预先固定金额更复杂,那么此可能的效率低于现有代码。但是如果您现有的代码基本上反复调用向量上的push_back
,那么这个基于模板的代码应该是一样好的。
答案 2 :(得分:3)
是时候发布关于RVO的答案了,我也是......
如果按值返回一个对象,编译器通常会优化它,因此它不会被构造两次,因为在函数中构造它作为临时函数是多余的,然后复制它。这称为返回值优化:将移动创建的对象而不是复制。
答案 3 :(得分:1)
一个常见的C ++之前的习惯用法是将引用传递给正在填充的对象。
然后没有复制载体。
void f( std::vector & result )
{
/*
Insert elements into result
*/
}
答案 4 :(得分:0)
如果编译器支持Named Return Value Optimization
(http://msdn.microsoft.com/en-us/library/ms364057(v=vs.80).aspx),你可以直接返回向量提供没有:
NRVO优化冗余拷贝构造函数和析构函数调用,从而提高整体性能。
你的例子中应该没有真正的差异。
答案 5 :(得分:0)
vector<string> getseq(char * db_file)
如果你想在main()上打印它,你应该循环播放。
int main() {
vector<string> str_vec = getseq(argv[1]);
for(vector<string>::iterator it = str_vec.begin(); it != str_vec.end(); it++) {
cout << *it << endl;
}
}
答案 6 :(得分:0)
是的,按价值返回。编译器可以自动处理它。
答案 7 :(得分:0)
IAsyncCollector
答案 8 :(得分:-1)
和#34一样好;按价值回报&#34;可能是,它可能导致一个错误的代码。请考虑以下程序:
#include <string>
#include <vector>
#include <iostream>
using namespace std;
static std::vector<std::string> strings;
std::vector<std::string> vecFunc(void) { return strings; };
int main(int argc, char * argv[]){
// set up the vector of strings to hold however
// many strings the user provides on the command line
for(int idx=1; (idx<argc); ++idx){
strings.push_back(argv[idx]);
}
// now, iterate the strings and print them using the vector function
// as accessor
for(std::vector<std::string>::interator idx=vecFunc().begin(); (idx!=vecFunc().end()); ++idx){
cout << "Addr: " << idx->c_str() << std::endl;
cout << "Val: " << *idx << std::endl;
}
return 0;
};
即使使用GNU g ++报告选项-Wall -Wextra -Weffc ++
,上述错误程序也表示没有错误如果你必须产生一个值,那么以下代码可以代替两次调用vecFunc():
std::vector<std::string> lclvec(vecFunc());
for(std::vector<std::string>::iterator idx=lclvec.begin(); (idx!=lclvec.end()); ++idx)...
上面在循环迭代期间也没有产生匿名对象,但需要一个可能的复制操作(正如一些说明的那样,在某些情况下可能会优化掉。但是引用方法保证不会产生任何副本。相信编译器将执行RVO无法替代尝试构建最有效的代码。如果您不需要编译器来执行RVO,那么您就领先于游戏。