【问题标题】:Pass by value or const reference? [duplicate]通过值或常量引用传递? [复制]
【发布时间】:2013-09-10 15:05:27
【问题描述】:

a set of good rules to determine whether pass by value or const reference

  • 如果函数打算更改参数作为副作用,请采取 它通过非常量引用。
  • 如果函数没有修改它的参数并且参数是 原始类型,按值取值。
  • 否则通过 const 引用获取,但以下情况除外 案例:如果函数需要复制 const 无论如何参考,按价值取值。

如下构造函数,如何确定?

class A
{
public:
    A(string str) : mStr(str) {} // here which is better, 
                                 // pass by value or const reference?

    void setString(string str)  { mStr = str; } // how about here?

private:
    string mStr;
};

【问题讨论】:

  • 构造函数平均比mStr(std::move(str)) 更好。如果你真的需要进一步优化,你仍然可以重载它。
  • 无论如何你都得拿一份,不是吗?
  • @chris 我认为您的move 方式也适用于setString。如果string 没有 move ctor 和 assignment,哪种方式更好?谢谢。
  • 是的,我没怎么看赋值运算符,但我想它会的。无论如何,我可能会说一个 const 引用。

标签: c++ parameter-passing


【解决方案1】:

在这种特殊情况下,假设 C++11 并移动字符串的构造/赋值,您应该按值获取参数并将其移动到构造函数的成员。

A::A(string str) : mStr(std::move(str)) {}

setter 的情况有点棘手,我不确定你是否真的想要/需要优化它的每一点......如果你想优化最多,你可以提供两个重载,一个采用右值引用另一个采用 const 左值引用。无论如何,const 左值引用可能是一个足够好的方法:

void A::setString(string const& str) { mStr = str; }

为什么会有差异?

在构造函数的情况下,成员尚未构建,因此需要分配内存。您可以将该内存分配(以及数据的实际复制,但这是租用者成本)移动到接口,这样如果调用者有一个临时的,它可以被转发而无需额外的内存分配。

在分配的情况下,事情有点复杂。如果字符串的当前大小足以容纳新值,则不需要分配,但如果字符串不够大,则需要重新分配。如果分配被移动到接口(按值参数),它将被执行总是,即使它是不必要的。如果分配是在函数内部完成的(const 引用参数),那么对于一小部分情况(参数是临时的,大于当前缓冲区的情况),本来可以避免的分配将被完成。

【讨论】:

    【解决方案2】:

    您站点的文章不是软件的良好参考 工程。 (它也可能已经过时了,因为它 谈论移动语义,从 2003 年开始。)

    一般规则很简单:通过 const 引用传递类类型, 和其他类型的值。有明确的例外:在 符合标准库的约定,它也是 通常按值传递迭代器和函数对象。

    其他任何事情都是优化,不应该进行,直到 探查器说你必须这样做。

    【讨论】:

      【解决方案3】:

      在这种情况下,最好通过 const 引用传递参数。原因:string是类类型,不用修改,可以任意大。

      【讨论】:

      • 我不同意;如果您无论如何要复制(或移动)参数和want speed, pass by value
      • @Angew,该链接似乎已损坏。我收到一个数据库错误。
      • 我不确定编译器是否能够避免双重复制。
      • @patrickvacek 哎呀。我当然希望那是暂时的;这是一篇很棒的文章。完整的标题是“想要速度?通过价值”。这似乎是a mirror
      • @Manu343726 这几乎可以在不重载的情况下实现,方法是在创建“副本”时按值获取参数并std::move()-ing 它。
      【解决方案4】:

      最好使用成员初始化列表来初始化您的值,因为它具有以下优点:

      1) 赋值版本,创建一个默认构造函数来初始化 mStr,然后在默认构造的之上分配一个新值。使用 MIL 可以避免这种浪费的构造,因为列表中的参数被用作构造函数参数。

      2) 它是唯一初始化常量变量的地方,除非这些只是整数,你可以在类中使用枚举。枚举 T{v=2};

      3) 这是初始化引用的地方。

      这是我的建议:

      #include <iostream>
      #include <string>
      
      class A
      {
         private:
            std::string mStr;
      
         public:
            A(std::string str):mStr(str){}
      
            //if you are using an older version of C++11, then use 
            //std::string &str instead
            inline const void setString(std::string str)
            {
               mStr = str;
            }
      
            const std::string getString() const
            {
               return mStr;
            }
      };
      
      int main()
      {
         A a("this is a 1st test.");
      
         a.setString("this is a 2nd test.");
      
         std::cout<<a.getString()<<std::endl;
      }
      

      看看这个: http://www.cplusplus.com/forum/articles/17820/

      【讨论】:

        猜你喜欢
        • 2011-06-20
        • 2013-08-01
        • 2015-03-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-21
        • 2011-07-11
        • 2012-03-30
        相关资源
        最近更新 更多