【问题标题】:Should I pass a string by value or pass a pointer to it?我应该按值传递字符串还是传递指向它的指针?
【发布时间】:2014-12-09 09:12:00
【问题描述】:

我有一个看起来像这样的函数

int myclass::setVersion(std::string ver)
{
  if (ver.size()>1)
  {
    version.swap(ver)
    return 0;
  }
  else 
    return -1;
}

我的问题很简单,是按原样传递ver 更好还是将它作为指向字符串的指针传递更好?仅供参考,ver 是一个小字符串(大约 8 个)。 编辑:ver 是否更改无关紧要。我只想用ver 的内容替换version。 EDIT2:我正在使用 Visual Studio 2008。

【问题讨论】:

  • 这不是“更好”的问题。如果该函数应该修改它的参数,那么它必须通过引用(或指针,如果你坚持的话)传递。如果不是,则必须按值传递。
  • 在您的原始问题中,您的标题提到了数组,但问题中没有数组。

标签: c++ string parameter-passing


【解决方案1】:

这取决于您希望代码的行为是什么。

此处建议的大多数答案都会更改您发布的代码的行为,因为它们将修改传入的字符串(或使代码无法编译,因为它无法修改传入的参数)。

在您发布的示例中,传递给myclass::setVersion()的字符串不会被修改(参数可能会被修改,但这只是传入字符串的副本;该副本将在函数返回时销毁) .

对于这样的情况,我建议传递const std::string&

int myclass::setVersion(std::string const& ver)
{
  if (ver.size()>1)
  {
    version = ver;
    return 0;
  }
  else 
    return -1;
}

这种方式只在必要时进行复制。

但老实说,除非经常调用该函数,否则可能没什么好担心的。

【讨论】:

  • 但老实说,除非经常调用该函数,否则可能没什么好担心的。这正是我的想法。我的意思是我假设版本字符串不会是 KB 或不会被调用一百万次,因此复制的影响几乎为零。
  • 从这个答案开始。如果测量结果表明您需要优化传递右值的情况,则添加右值引用重载。
  • 我的经验法则是“默认”使用const&。如果函数最终总是复制参数以制作可修改的副本,那么参数将改为按值传递。其他细节(比如调用者的参数需要修改,或者为了更好地支持具有 C++11 移动语义的右值参数)将导致这些细节发生变化或重载以覆盖额外的要求。
【解决方案2】:

在 C++11 中,您可以添加一个接受右值引用的重载:

int myclass::setVersion(std::string& ver);
int myclass::setVersion(std::string&& ver);

这样您就可以从右值和左值交换。实际上,您可以执行移动分配,而不是 swap

version = std::move(ver);

这可能比swap 更快,具体取决于std::string 的实现。

使用示例:

string getVersion() { return "version2"; }

string v1 = "version1";
a.setVersion(v1);           // lvalue
a.setVersion(getVersion()); // rvalue
a.setVersion("version3");   // rvalue as well

Demo

更新:确实,您必须同时拥有setVersion 的两种变体以获得最大的灵活性。但我同意其他人的观点,所有这些都是过早的优化,只有在分析显示此时出现瓶颈时才应使用。

【讨论】:

  • 这种方法通过const引用传递和分配字符串有什么好处?
  • @NeilKirk 交换可能比复制更快。实际上,setVersion 的实现甚至比使用移动语义交换更快。
  • 请注意,如果您希望能够在不移动它的情况下传入v1(使用std::move())并因此获得它的值,那么根据这个建议,您需要一个采用标准引用的重载不确定。
  • 编写一个采用右值的函数通常是一种过早的优化,并且由于需要复制以获得那些宝贵的右值,甚至会导致代码变慢且安全性降低。仅仅因为存在新功能并不意味着您应该在任何地方使用它,正如@MichaelBurr 所说,const& 仍然应该是您的默认设置。
  • @MichaelBurr 谢谢,代码和演示已修复,添加脚注。
【解决方案3】:

请提供参考。

int myclass::setVersion(std::string& ver)

【讨论】:

  • 谢谢,请问原因?
  • 您可以将其设为 const 引用:int myclass::setVersion(const std::string& ver)
  • @w.b:不,你不能; swap想修改。
  • 这是正确的答案如果函数应该修改它的参数。我们不知道是不是这样。
  • 请看这个问题的答案reference or pointer。希望对您有所帮助。
【解决方案4】:

当您修改字符串并希望调用者看到该更改时,您应该通过引用传递它。

【讨论】:

    【解决方案5】:

    您想将ver 的内容存储到版本中。必须制作副本,问题是在哪里。

    您可以按照自己的建议进行操作,因为交换速度很快。但我注意到并非所有控制路径都会导致版本字符串被分配一个新值。

    所以我建议如下

    int myclass::setVersion(const std::string& ver)
    {
      if (ver.size()>1)
      {
        version = ver;
        return 0;
      }
      else 
        return -1;
    }
    

    如果ver的大小为1,这将避免复制,在这种情况下,您不想将字符串复制到版本中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-25
      • 2021-03-09
      相关资源
      最近更新 更多