Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/157.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在c++;_C++_Return Value_Stdvector - Fatal编程技术网

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
  */
} 

现在是我发布答案的时候了,我也是


如果您按值返回一个对象,编译器通常会对此进行优化,这样它就不会被构造两次,因为在函数中将它构造为临时对象然后复制它是多余的。这称为返回值优化:创建的对象将被移动而不是复制。

如果编译器支持命名的返回值优化(),则可以直接返回向量,前提是没有:

  • 返回不同命名对象的不同路径
  • 多个返回路径(即使在 引入EH状态的所有路径)
  • 返回的命名对象在内联asm块中引用
  • NRVO优化了冗余复制构造函数和析构函数调用,从而提高了总体性能


    在您的示例中应该没有实际的差异。

    您应该按值返回

    该标准具有提高按值返回效率的特定功能。它被称为“复制省略”,在本例中更具体地说是“命名返回值优化(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;(idx
    vector 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()) ;
       }