为什么通过引用传递字符串并使其成为常量?

时间:2013-10-07 00:46:45

标签: c++

只是一个普遍的问题,一个函数的签名是:

void f( const string & s )...

如果您实际上没有更改字符串(因为它是常量),为什么有必要通过引用传递它?

5 个答案:

答案 0 :(得分:6)

通过引用传递有两种方法 - 通过指针传递,并通过值传递。

通过指针传递类似于通过引用传递:可以为它做出“如果你不想修改它,为什么传递指针”的相同参数。

按值传递需要复制。复制字符串通常更昂贵,因为需要在封面下分配和取消分配动态内存。这就是为什么传递const引用/指针通常比传递您不打算更改的副本更好的原因。

答案 1 :(得分:3)

按值传递变量时,它会复制。通过引用传递避免了该副本。您希望将其标记为const,原因相同:由于您没有制作副本,因此您不希望意外地弄乱原件。我认为这也可能允许编译器优化。

intcharfloat以及其他原始类型通常不会看到这一点的原因是它们复制相对便宜,在某些情况下,通过引用传递更昂贵(例如,通过引用传递char可能涉及传递64位数据(指针)而不是8位。通过引用传递也会增加一些间接,这不是一个像字符串这样的大字体很重要,但对int这样的东西很浪费。

答案 2 :(得分:1)

这不是“必要的”,但常见的答案是“出于性能原因,防止复制”,但这是一个天真的答案而且事实有点复杂。

在您的示例中,假设s确实是不可变的,而您不“拥有或不能更改”,则const装饰器适用于s。如果没有采用s的引用,则可以保证复制(不包括编译器优化)。

如果f()s返回后不会使用f()的副本,那么复制s的工作就会被浪费掉。因此,通过引用传递可以防止复制,f()保留检查字符串s的能力。大。再一次,这是天真的答案和前C ++ 11,将是最正确的答案。

为了回答“是否有必要?”还有更多值得考虑的情景。但我只关注一个:

  

如果f()的调用者在调用后不需要字符串s   f(),但f()需要保留数据副本。

假设代码是:

void f(const std::string& arg1);   // f()'s signature
void g(const std::string& arg1) {
   std::string s(arg1);
   s.append(" mutate s");
   f(s);
}

在这种情况下,您将构建字符串s,并通过const引用传递给f(),如果您假设f(),从性能角度来看一切正常}是不透明的,没有进一步的优化。

现在,假设f()需要s中的数据副本,那么是什么?好吧,f()将调用复制构造函数并将s复制到局部变量中:

 // Hypothetical f()
 void f(const std::string& s) {
   this->someString_ = s;
 }

在这种情况下,当数据存储在someString_时,将在g()中调用普通构造函数,并且将在f()中调用复制ctor,但g()所做的工作将被浪费掉。为了提高性能,可以做两件事,按值传递和/或使用移动构造函数。

// Explicitly move arg1 in to someString_
void f(std::string&& arg1) {
  this->somestring_ = std::move(arg1);
}

void g(const std::string& arg1) {
   std::string s(arg1);
   s.append(" mutate s");
   f(s);
}

显式执行编译器将从C++11开始自动执行的操作,这意味着更正确的版本将通过值传递并让编译器执行正确的操作:

void f(std::string arg1) {
  this->somestring_ = arg1; // Implicit move, let the compiler do the right thing
}

void g(const std::string& arg1) {
   std::string s(arg1);
   s.append(" mutate s");
   f(s);
}

在这种情况下,字符串是在g()中构建的,并且在任何地方都没有进行任何额外的工作。所以在这种情况下,回答,

  

如果你实际上没有必要通过引用传递它   更改字符串(因为它是常量)?

字符串未更改,但已被复制,因此无需 const引用

阅读器列出了在调用sf()变为或​​未变异时编译器可以采取的优化。

我不能建议人们查看David Abrams的帖子,“Want Speed? Pass by value”或Is it better in C++ to pass by value or pass by constant reference?并发布How to pass objects to functions in C++?

答案 3 :(得分:0)

换句话说,你会得到通过引用传递的速度(不会产生额外的副本)。 和值传递的完整性(原始变量值不变)

答案 4 :(得分:0)

这不是必要的,但这是一个非常好的主意,原因如下:

  1. 效率。不创建或销毁新字符串比创建和销毁它们更有效,尤其是字符串长度任意,因此需要动态分配内存。
  2. 可以从字符串文字构造string。如果指定const,则允许编译器从文字构造临时string,以便调用者可以只提供文字而不是string对象。如果您未指定const,则编译器无法执行此操作,因此调用方也无法执行此操作。