在C++中什么时候需要使用引用?

3

我经常不确定何时应该引用,何时应该使用变量传递。例如,JOBJECTs调用其中一个API:

QLIST retrive_cinemas(QString& options)
{
   return (staticobject::getcinemas(options));
}

或者

QLIST retrive_cinemas(QString options)
{
   return (staticobject::getcinemas(options));
}

我假设大部分时间你会想使用引用。与Java不同,你需要有指针/地址。现在指针与地址是不同的故事。 - Moonhead
阅读整个章节,您将理解: http://www.drbio.cornell.edu/pl47/programming/TICPP-2nd-ed-Vol-one-html/Frames.html - iDebD_gh
如果方法有 void someMethod(TYPE *parameter),请使用指针。您的变量本身可以是一个指针:TYPE *option1; TYPE option2;。如果参数和选项都是指针(有星号),只需使用 someMethod(option1);。否则,请使用 someMethod(&option2); - Sebastian Lange
按引用传递在同一对象上工作,而按值传递则复制整个对象。由于本机QT对象可以相当大,因此引用传递速度更快。如果您不修改对象,请使用const引用。https://dev59.com/s3RC5IYBdhLWcg3wOOP1 - Sebastian Lange
在这个特定的例子中,没有影响,因为QString使用了写时复制(隐式共享)语义。 - cmannett85
@cmannett85 这不是真的。通过值传递任何隐式共享类都会导致所有核心之间缓存行同步的等效代价,因为引用计数的原子增量。如果经常这样做,它对所有核心的性能都有可测量的影响。因此,如果没有必要,这是一件相当糟糕的事情。如果你所说的是真的,那么Qt代码本身就不会通过const引用传递所有这些隐式共享对象! - Kuba hasn't forgotten Monica
3个回答

4

我觉得你的问题可以简化为以下内容:

你有一个函数/方法 f(),还有一个类 X,你想知道何时应该将 X 作为引用传递给 f()

你可以确定三个选项:

void f(X v)            // #1 - pass by value
void f(const X& cr)    // #2 - pass by const reference (&)
void f(X& r)           // #3 - pass by reference (&)

如果 X 是容易复制的(例如它是一个 int,一个 double 等),并且您不想修改它,则通过值传递 (#1)。如果 X 不容易复制(例如它是一个 vector,一个 string 等),并且您不想修改它,则通过 const 引用传递 (#2)。如果您想要在 f() 中修改类型为 X 的参数,则通过引用传递。
在您发布的特定代码中,由于QString是一个完整的类,与例如intdouble相比,它不便宜(即使它使用COW技术和“隐式共享”,我认为复制仍然意味着调用类似于Win32InterlockedIncrement()这样的东西来以线程安全的原子方式增加引用计数),如果您不想在函数内部修改它,则应该通过const引用(即const QString &,#2)传递它。
如果您想在函数的主体内修改它,只需通过引用传递(QString&,#3)。

我认为你的编辑有点误导性。即使不像通过引用传递那样便宜,QString 仍然非常便宜易于复制。引用计数使用原子增量和减量,这比使用锁实现的线程安全更快。因此,它真的并不是那么“糟糕”。 - dtech
@ddriver:正如你所写的,引用计数(需要原子增减)比简单的传递(const)引用要慢。我不喜欢在C++代码中出现“过早的悲观主义” :)。 - Mr.C64
当你说“不便宜”时,你意味着“昂贵”,但实际上并非如此。虽然隐式共享不像通过引用传递那样便宜,但它仍然是一种廉价的方式。我不能保证你想要表达什么,我只是告诉你作为第三人阅读你的评论时你听起来在暗示什么。 - dtech
对我而言,int或者double是_便宜_的复制对象。涉及调用交换原子操作(例如Win32 InterlockedIncrement())的内容则_不是_便宜的复制对象,或者至少比简单的const& 传递 更加昂贵。 - Mr.C64
@ddriver:我希望你知道COW是一种性能下降的多线程技术,并且在现代C++11中,禁止使用COW来处理std::string - Mr.C64
显示剩余3条评论

3
在Qt中,答案取决于您想要传递的对象是否使用了“隐式共享”:
许多Qt中的C++类使用隐式数据共享来最大化资源使用和最小化复制。当作为参数传递时,隐式共享类既安全又高效,因为只传递指向数据的指针,并且仅在函数写入数据时才复制数据,即写时复制。
您可以通过引用传递对象使用隐式共享,但不一定需要这样做。它们被设计为能够有效地按值传递!
此处,您可以找到完整的解释以及使用隐式共享的类列表。QString使用隐式共享。

4
隐式共享对象按值传递仍然比按引用传递效率低。如果你在紧密循环中经常使用它,性能将有明显差异。 - dtech
1
在Qt中,当传递方法参数时,将其作为const引用传递仍然是惯用的。对于返回值,省略const引用(这也给予更多的实现自由 - 否则你必须返回一个类成员!) - Frank Osterfeld

0
在Qt中,字符串是隐式共享的,在编辑时自动复制,因此即使按值传递也是安全的。 不过最好还是按引用传递(以防它不是QString),而且更有效率,因为复制的数据量更少,只有一个内存地址与大小和引用计数。
一般来说,当您想要修改函数内部的实际对象时,最好按引用传递(请注意,如果您通过值传递隐式共享的QString并在函数内部进行修改,则不会修改原始字符串,而是复制它,并且更改将在函数返回后丢失(除非您当然返回新字符串))。使用引用比使用指针更方便,也更安全。此外,如果对象大于基元或对象不能/不应复制,则可以按引用传递。如果您不想修改源对象,请将引用设置为const。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接