【问题标题】:What is the best way to return string in C++?在 C++ 中返回字符串的最佳方法是什么?
【发布时间】:2012-05-11 14:14:09
【问题描述】:

我的问题很简单:如果我有一些类 Man 并且我想定义返回人名的成员函数,我更喜欢以下两种变体中的哪一种?

第一:

string name();

第二:

void name(/* OUT */ string &name);

第一个变体有点低效,因为它会产生不必要的副本(局部变量 -> 返回值 -> 赋值左侧的变量)。

第二个变种看起来很有效,但写起来让我哭了

string name;
john.name(name);

而不是简单

string name(john.name());

那么,我应该更喜欢哪种变体?在效率和便利性/可读性之间进行适当的权衡是什么?

提前致谢。

【问题讨论】:

  • 旁注,因为name() 看起来像一个查询,所以将其设为const: string name() const;
  • @hmjd 为什么是第一个const?返回的对象最终属于客户,他应该可以随意使用它。
  • @JamesKanze,这不是签名的一部分,而是我的评论,后面跟着一个':'。
  • 如果只是一个简单的 getter 访问相应的成员变量,const std::string& 可能是一个更好的主意。
  • @hmjd 对不起,那么。在我使用的字体中, : 显示得不太好。

标签: c++ string


【解决方案1】:

这是一个很好的问题,您提出这个问题表明您正在关注您的代码。不过,好消息是,在这种特殊情况下,有一个简单的出路。

第一个干净的方法是正确的方法。 The compiler will eliminate unnecessary copies,在大多数情况下(通常在有意义的地方)。

编辑(2016 年 6 月 25 日)

不幸的是,David Abaraham 的网站似乎已经离线几年了,而那篇文章已经丢失了(没有可用的 archive.org 副本)。我冒昧地将我的本地副本上传为 PDF 用于存档目的,它是can be found here

【讨论】:

  • 是的,这篇文章写得非常好,真的一针见血。
  • 谢谢!我已经阅读了这篇文章并且非常感到困惑,但它确实清理了一切。现在我必须清理我的 高效 代码 =)
  • 当然,对于重量级的变量,我总是会使用“第二个变体”。我觉得这种方法甚至可以自我注释,因为读者会认为数据类型是重量级的。至少,我的意见。
【解决方案2】:

使用第一个变体:

string name();

编译器很可能会优化掉任何不必要的副本。见return value optimization

在 C++11 中,移动语义意味着即使编译器不执行 RVO,您也不执行完整复制。见move semantics

还要记住,如果替代方案是

void name(std::string& s);

那么你必须非常清楚地指定s 会发生什么以及传递给函数时它可以具有什么值,并且可能进行大量有效性检查,或者只是完全覆盖输入。

【讨论】:

    【解决方案3】:

    既然你想为你的类的一个字段创建一个 getter,也许你应该这样做:inline const std::string& name() const { return this->name; }

    由于名称是作为 const 引用返回的,因此不会在类外修改,也不会通过返回名称来创建副本。

    之后,如果你想操纵名称,你将不得不做一个副本。

    【讨论】:

    • 感谢您的回答!这是有道理的,但我考虑了在函数内部计算名称时的一些情况,例如'fullname()' 函数返回姓氏和名字并在一起。
    • 是的,在这种情况下,您必须返回该值,因为从函数返回后,对局部变量的引用将无效。您的问题的替代方法是在每次修改名字或姓氏时计算全名(您可以在setNamesetFirstName 方法中执行此操作)并将其存储在全名字段中。这样,您不必每次调用 fullname() 时都重新计算全名,您只需返回对全名字段的 const 引用(如我的回答中所述)。
    【解决方案4】:

    我会选择第一个。返回值优化和 C++11 将消除任何复制开销。

    【讨论】:

      【解决方案5】:

      由于我们有移动语义(在 C++11 中),你可以使用这个:

      string name();
      

      即使在 C++03 中,这也差不多,因为编译器可能会对此进行优化(搜索返回值优化)。

      【讨论】:

        【解决方案6】:

        优化规则#1:衡量,优化,衡量。或者,正如 Knuth 所说,“过早的优化是万恶之源”。

        除非您有强烈的迹象表明简单地返回 std::string 会显着影响您的软件的性能,否则请这样做。如果您可以衡量重大影响,请找到关键路径并优化那个。不要进行任何有趣的、项目范围的“优化”,因为这些优化可能对性能几乎没有好处,但会对代码的可读性、可维护性和健壮性产生负面影响。

        【讨论】:

          【解决方案7】:

          我认为您应该使用第一个变体。因为这是简单的 getter 方法,所以到处都在使用这种 getter/setter 方法。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-09-05
            • 1970-01-01
            • 2011-03-13
            • 2012-08-13
            • 2014-03-19
            • 2014-03-01
            • 1970-01-01
            • 2010-09-30
            相关资源
            最近更新 更多