C ++左值,右值,引用,参数和性能

时间:2015-09-27 17:46:52

标签: c++ c++11 parameters lvalue rvalue

所以我有一个需要将std :: vector作为参数的函数。我想知道声明参数的最佳方法,以便底层数组不会被深度复制,因为它可能相当大。

// which should I choose?
void myFunc(std::vector<char>); // 1
void myFunc(std::vector<char>&); // 2
void myFunc(std::vector<char>&&);  // 3
void myFunc(std::vector<char>*) // 4

我应该选择哪个?另外,我不会修改函数中的向量,所以不应该添加const?我应该重载该函数并将它们组合在一起吗?

2 个答案:

答案 0 :(得分:6)

  1. 如果您打算在函数内复制它:

    void myFunc(std::vector<char>);
    
  2. 如果您只想阅读参数而不复制它:

    void myFunc(const std::vector<char>&);
    
  3. 如果要修改传递给函数的原始矢量:

    void myFunc(std::vector<char>&);
    
  4. 如果您想要move函数中的enter image description here优化rvalues

    void myFunc(std::vector<char>&&);
    
  5. 如果您需要能够表示通过引用传递的可选参数:

    void myFunc(const std::vector<char>*);
    
  6. 如果你需要传递一个你想要修改的可选参数 - nullptr

    void myFunc(std::vector<char>*);
    

答案 1 :(得分:2)

如果您想要深层复制 std::vector

  • 移动到您的函数中:

    // foo() decalaration
    void foo(std::vector<int> v);
    
    // usage example
    std::vector<int> v {0, 1, 2, 3};
    foo(std::move(v));
    // v is moved into foo() and invalid now
    

    您也可以以相同的方式从函数返回此向量:

    // foo() decalaration
    std::vector<int> foo(std::vector<int> v) {
        return v.push_back(4), std::move(v);
    }
    
    // usage example
    std::vector<int> v {0, 1, 2, 3};
    v = foo(std::move(v));
    // now v is {0, 1, 2, 3, 4} and no one were deep copied
    

    但请注意,如果您不移动(请致电foo(v)而不是foo(std::move(v))),那么它将被深度复制。在幕后,v的参数foo()仅由 move-constructor 构建。

  • 将其作为参考传递:

    // foo() declaration
    void foo(std::vector<int>& v);
    

    但是现在我们遇到了一个问题:哪个引用和 cv-qualifiers ?好吧,一般来说,我们有2种类型的引用和4种类型的 cv-qualifiers ,总共有8种声明:

    void foo(std::vector<int>&);
    void foo(std::vector<int> const&);
    void foo(std::vector<int> volatile&);
    void foo(std::vector<int> const volatile&);
    void foo(std::vector<int>&&);
    void foo(std::vector<int> const&&);
    void foo(std::vector<int> volatile&&);
    void foo(std::vector<int> const volatile&&);
    

    当然,其中一部分是无用的,应该删除。但是,太多的声明也被称为完美转发问题(实际上,当它出现问题时没有rvalue-references,因此问题小了2倍)。

    例如,如果要修改v,则至少需要2个函数:

    void foo(std::vector<int>&);
    void foo(std::vector<int>&&);
    

    在这种情况下,您可以在左值对象上调用foo()

    std::vector<int> v;
    foo(v);
    

    以及临时:

    foo(std::vector<int>{1, 2, 3, 4, 5});
    

    但是如何代码只是一个针对不同引用类型和/或cv-qualifiers的实现?让我介绍通用引用

    template<typename Vector>
    void foo(Vector&& v);
    

    Vector&& 始终是参考类型,可以推断为

    • std::vector<int>&如果您将std::vector<int>类型的左值传递到foo()

      std::vector<int> v; 
      foo(v); // v is lvalue
      
    • std::vector<int> const&如果您传递std::vector<int>类型的const左值:

      std::vector<int> const v; 
      foo(v); // v is const lvalue
      
    • std::vector<int>&&如果您传递rvalue:

      foo(std::vector<int>{0, 1, 2}); // v is rvalue
      
    • 等...

    但在这种情况下,您必须检查Vector类型的接受程度。但这是另一个故事。

在这种情况下,我绝对没有理由传递指针而不是引用。