C++ 在c++;
在函数中返回C++ 在c++;,c++,return-value,stdvector,C++,Return Value,Stdvector,在函数中返回std::vector时复制了多少数据,将std::vector放在空闲存储区(堆上)并返回指针会有多大的优化,即: std::vector *f() { std::vector *result = new std::vector(); /* Insert elements into result */ return result; } 效率高于: std::vector f() { std::vector result; /* Inser
std::vector
时复制了多少数据,将std::vector放在空闲存储区(堆上)并返回指针会有多大的优化,即:
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;
}
在C++11中,这是首选的方式:
std::vector<X> f();
std::vector f();
也就是说,按值返回
对于C++11,
std::vector
具有移动语义,这意味着函数中声明的局部向量将在返回时移动,在某些情况下,编译器甚至可以省略移动。C++11之前的一个常见习惯用法是传递对正在填充的对象的引用
那么就没有向量的复制了
void f( std::vector & result )
{
/*
Insert elements into result
*/
}
现在是我发布答案的时候了,我也是
如果您按值返回一个对象,编译器通常会对此进行优化,这样它就不会被构造两次,因为在函数中将它构造为临时对象然后复制它是多余的。这称为返回值优化:创建的对象将被移动而不是复制。如果编译器支持命名的返回值优化(),则可以直接返回向量,前提是没有:
在您的示例中应该没有实际的差异。您应该按值返回 该标准具有提高按值返回效率的特定功能。它被称为“复制省略”,在本例中更具体地说是“命名返回值优化(NRVO)” 编译器不必实现它,但编译器也不必实现函数内联(或执行任何优化)。但是,如果编译器不进行优化,标准库的性能可能会非常差,所有严肃的编译器都实现内联和NRVO(以及其他优化) 当应用NRVO时,以下代码中不会有复制:
std::vector<int> f() {
std::vector<int> result;
... populate the vector ...
return result;
}
std::vector<int> myvec = f();
还有另一种选择,即为用户提供更灵活的界面:
template <typename OutputIterator> void f(OutputIterator it) {
... write elements to the iterator like this ...
*it++ = 0;
*it++ = 1;
}
模板无效f(输出迭代器it){
…像这样将元素写入迭代器。。。
*it++=0;
*it++=1;
}
除此之外,您还可以支持现有的基于向量的接口:
std::vector<int> f() {
std::vector<int> result;
f(std::back_inserter(result));
return result;
}
std::vector f(){
std::向量结果;
f(标准:背向插入器(结果));
返回结果;
}
如果现有代码使用reserve()
的方式比预先确定的数量更复杂,那么这可能比现有代码的效率低。但是,如果您现有的代码基本上重复调用向量上的push_back
,那么这种基于模板的代码应该是一样好的。就像“按值返回”一样好,这种代码可能会导致错误。考虑下面的程序:
#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;
};
#包括
#包括
#包括
使用名称空间std;
静态std::向量字符串;
向量vecFunc(void){返回字符串;};
int main(int argc,char*argv[]){
//设置字符串的向量以保持不变
//用户在命令行上提供的许多字符串
for(int idx=1;(idxvector getseq(char*db_文件)
如果你想在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;
}
}
intmain(){
向量str_vec=getseq(argv[1]);
for(vector::iterator it=str_vec.begin();it!=str_vec.end();it++){
cout向量func1()常量
{
向量部分;
返回向量(parts.begin(),parts.end());
}
这在c++11以后仍然有效,因为编译器会自动使用move而不是复制。通过引用传递向量,然后将其填充到f
中如何?这是一个非常基本的优化,大多数编译器随时都可以进行。随着答案的不断涌现,它可能会帮助您澄清您是否正在使用ng C++03或C++11。这两个版本之间的最佳实践差异很大。请参阅@Kiril Kirov,我可以不将它放入函数的参数列表中就这样做吗?void f(std::vector&result)?即使没有std::move
,它也会被移动吗?@LeonidVolnitsky:如果它是本地的,则是。事实上,返回std::move(v);
将禁用移动省略,即使只返回v;
也是可能的。因此后者是首选。@juanchopanza:我不这么认为。在C++11之前,你可以反对它,因为向量不会移动;而RVO依赖于编译器!谈谈80年代和90年代的事情。我对返回值的理解(按价值计算)is:被调用方中的返回值不是“已移动”,而是在调用方的堆栈上创建的,因此被调用方中的所有操作都已就绪,在RVO中没有可移动的内容。这是否正确?@r0ng:是的,这是正确的。编译器通常是这样实现RVO的。这在C++11中不再是一个习惯用法。@Nawaz我同意。我不确定最好的做法是什么E现在是关于C++的问题,但不是特别是C++ 11。我怀疑我应该倾向于给C++ 11答案,C++ 03对生产代码中的某人进行深度的回答。你有什么意见吗?实际上,在C++ 11(19个月大)发布之后。我认为每个问题都是C++ 11问题,除非它被明确地表述为C++ 03问题。它是真正最好和详细的答案。但是,在你的SWAP()变量中(对于没有NRVO的C++ 03),你仍然会有一个复制构造器拷贝在f-()中进行。:从变量结果到一个隐藏的临时对象,该对象最终将被交换到myvec。@JenyaKh:当然,这是一个实现质量问题。标准不要求C++03实现
#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;
};
std::vector<std::string> lclvec(vecFunc());
for(std::vector<std::string>::iterator idx=lclvec.begin(); (idx!=lclvec.end()); ++idx)...
vector<string> getseq(char * db_file)
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;
}
}
vector<string> func1() const
{
vector<string> parts;
return vector<string>(parts.begin(),parts.end()) ;
}