c++中为啥要函数返回引用?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c++中为啥要函数返回引用?相关的知识,希望对你有一定的参考价值。

参考技术A 1
c++标准中没有所谓的“c++为什么返回引用的函数的形参也必须是传引用”的规定。
2
在你的例子里(很奇怪的用法,为什么不直接
cp1
=
cp2;呢),不能去掉"&"的原因如下:
如果没了参数的"&",那么这个returnme函数所做的事情就是将cp1复制给临时对象a,
然后返回a的引用,之后相当于a
=
cp2;
再之后过了这一行,a
的生命周期完结了。
而cp1本身自然不受影响。
ps:
如果你对“生命周期”或者
返回局部对象的引用
这些概念不熟悉的话,请参阅
effective
c++(这本薄书看明白了,那baidu
c++
区的绝大多数问题都难不住你了)
参考技术B 1 返回变量的引用实际上相当返回变量的地址,通常是四个字节,如变量多于4个字节时,返回引用比返回值效率要快.
2 别外,返回引用另一个用处是外界可以使用这个引用改变原变量的内容,而值返回则不能修改内容.
const引用是要使用1中的效率,而防止2中外界修改这个变量的内容

为啥在返回右值引用时给出 C++ 编译器警告?

【中文标题】为啥在返回右值引用时给出 C++ 编译器警告?【英文标题】:Why give a C++ compiler warning when returning an rvalue reference?为什么在返回右值引用时给出 C++ 编译器警告? 【发布时间】:2015-07-03 10:41:24 【问题描述】:

我一直在研究右值引用(对我来说是一个新概念),并且对我在以下类函数中收到的警告感到困惑......

string&& Sampler::Serial() const 
    stringstream ss;
    .
    . [assemble a string value using data members]
    .
    return ss.str();

这编译成功,但出现以下警告...

..\Metrics\Sampler.cpp:71:16: warning: returning reference to temporary [-Wreturn-local-addr]
  return ss.str();
                ^

我完全清楚我正在返回一个临时的,这一点可以从我使用右值引用作为我的返回类型这一事实来证明。代码在执行时似乎运行良好,那么为什么要保证编译器警告呢?

similar questions 的标准答案似乎是复制返回值而不是使用引用,但是当我可以使用右值引用移动它时,为什么要复制潜在的大量临时数据呢?这不就是它被发明的原因吗?

【问题讨论】:

右值引用仍然是引用;临时没有神奇的生命周期延长,它在控制权返回给Serial()的调用者之前被销毁,所以你返回的引用总是悬空的。 您返回的不是临时的;您正在返回对临时的引用。你也没有移动任何东西。 我不确定我是否看到了 Johanne 对链接问题的回答中未讨论的问题。如果您简单地返回std::stringss.str(),您就不是在“复制可能大量”的任何东西。是什么让您认为如果正确调用移动语义会以某种方式适用? @Syndog 未定义的行为会产生令人讨厌的结果,通常会做你认为应该做的事情,直到它没有做。 @Syndog std::string 支持移动构造;您将从str() 返回的右值移动到您的 res 中,然后从 that 移动到调用者的目标中。 std::string 针对允许移动分配和移动构造进行了优化。简而言之,如果您仅使用std::stringreturn ss.str();,您几乎将不得不跳过障碍来强制这个not 做您想做的事情。 【参考方案1】:

没有移动您的数据。您正在创建一个本地对象,创建对该本地对象的引用,销毁该本地对象,然后仍在使用该引用。

您应该按值返回,正如您已经发现的那样。但不是复制,而是移动数据。这是确保您不会复制大量数据的安全方法。

std::string Sampler::Serial() const 
    std::stringstream ss;
    .
    . [assemble a string value using data members]
    .
    return std::move(ss.str());

注意:std::move 在技术上在这里是多余的,因为ss.str() 已经返回了一个右值,因此已经被移动了。无论如何,我建议保留它。这种方式适用于任何情况,因此您不必考虑使用哪种形式:如果要移动,请写move


正如 T.C. 所指出的,一般而言,尽管您的情况并非如此,但这可以防止 RVO。如果 RVO 是可能的并且编译器无论如何都会隐式使用移动,则无需显式编写 move。例如:

std::string f() 
  std::string x;
  ...
  return x; // not std::move(x)

在这里,读者应该已经清楚x 是一个局部变量。 C++ 代码在不写move 的情况下返回局部变量是正常的,因为编译器将完全忽略x 局部变量并直接在返回槽中构造std::string 对象(无论这对您的平台意味着什么),或者无论如何,编译器都会隐式使用 std::string 的移动构造函数。

【讨论】:

这会抑制 RVO。 @T.C. RVO 在这里已经不可能了,但公平点。如果 RVO 是可能的,请不要写 move。将编辑。 @hvd:这仍然可以防止复制省略,AFAIK。 @Xeo 嗯。是的,我认为你是对的,它会......该死。现在从根本上改变我的答案是不合适的,它会歪曲已经投下的选票(或者我被告知,无论如何),但是如果你想写一个不同的答案来解释为什么 not 在这里写 std::move,你会得到我的支持,然后 OP 希望能接受它。 @hvd 非常同意。我会留意的。【参考方案2】:

这类似于返回一个对局部变量的左值引用,让您快速了解未定义的行为。

无论您返回左值引用还是右值引用,您仍在引用将在函数退出时销毁的内存。

Rvalue 引用返回类型应该保留用于当您引用一个生命周期比函数长的对象但您不再需要它的情况下,因此为了提高效率而将其移出就可以了。例如,您可能会临时存储一些数据,但客户可以选择“窃取”您的数据。在这种情况下,返回对数据的右值引用是合理的。

【讨论】:

给这个 +1 的优秀简单的英语博览会。谢谢,TartanLlama!【参考方案3】:

您返回对在作用域结束时被销毁的临时对象 (ss) 的对象(由 str() 返回)的(右值)引用。

你应该返回对象:

string Sampler::Serial() const

【讨论】:

以上是关于c++中为啥要函数返回引用?的主要内容,如果未能解决你的问题,请参考以下文章

c++中重载输出流对象,为啥要返回引用

c++中为啥赋值运算符重载返回类型是引用

为啥在返回右值引用时给出 C++ 编译器警告?

C++里面,为啥重载前++时不返回引用就不能连用?

为啥赋值运算符要返回对对象的引用?

为啥 c++ 编译器不会警告返回对局部变量的引用?