C++返回值为Const &的看法 大虾们给解释下

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++返回值为Const &的看法 大虾们给解释下相关的知识,希望对你有一定的参考价值。

网上听某人说过只有迫不得已的情况下才会使用const&,为了提高效率传参时不调用拷贝构造,通常情况下返回或者传入引用。 但是也没有说明缘由,这让我很郁闷。

看上面的小例子:
大家都知道我们通常的返回值或者形参都是作为一个参考数据提供给外部,或者由外部传入使用,大部分计算都是封在对象内部,由内部对象去处理。我想不会有人愚蠢到写出如上图 fun(a) += 1;类似的代码吧?这么写的确没有太大意义,或许也有这样的特殊情况,形参作为 引用 传递是为了完成某些程序结构的特殊处理,这到没什么疑问,返回值作为引用传递,这让我很费解,有些人说是为了不调用拷贝构造,延长寿命什么的,我就郁闷了const & 也可以做到,为什么不用const& 呢?大多数变量返回值也都是作为一个数据的参考不会像上图fun函数一样直接参加运算(指针变量除外)。
至少我知道const& 的两个好处,一是不会调用拷贝,二是在不调用拷贝的情况下返回 本类型的任何级别的变量(普通变量,常量,引用变量)并且不会改变其值。
有一点我是不清楚的,也是我最担心的一点。普通变量形参在传递的过程 需要重新申请一个。
那么引用变量形参和const引用变量形参在传递的过程中是否也要经过一次申请呢? 如果不需要申请的话那么const&从哪里来呢?( 指针除外:本类型任何级别都可以作为形参传给const& )
求解?
O(∩_∩)O谢谢;

首先&的引用作用是C++独有的特性。其作用相当于传入参数时不经过拷贝,而是实实在在的传入。

就像LZ的例子中的fun(int &a)。如果在函数内部修改了a的值,那就确实修改了a的值。而一般的参数传入方式都是传入一个参数的副本。函数内部的操作都是作用于副本。
我对LZ的某些话有点难以理解,比如“普通变量形参在传递的过程 需要重新申请一个”
我猜测LZ的意思其实就是普通变量形参在传递的过程 传递的其实是参数的拷贝。
不过如果LZ既然已经知道这层意思,那么后面的疑问又从何而来。这不是显而易见的吗?
所以我感觉LZ压根没把引用的作用弄明白,所以才在上面说了一大堆。

对于返回值,也类似。一般返回值也是返回的拷贝值。所以如果将函数内的局部变量以引用方式返回是没有意义的。因为退出函数后,函数内部的局部变量已经被系统回收,所以这样引用方式传出的变量也是无效的。但是一般方式返回的变量反而是有效的。因为一般方式返回的是拷贝值,即使原版已经被销毁也无所谓。
但是,有种情况是个例外。那就是对于生命周期足够长的变量,引用返回就是有效的。比如LZ例子里的int& fun(int &a)return a;,这里的a因为是引用方式传入,所以他的生命周期是大于函数本身的。所以引用方式传出也没有问题。当然其实这个例子一般不常见。真正常见的是下面的例子:

class A

public:
A():m_data(0)
int m_data;
int &get() return m_data;

这里的m_data的生命周期和类A实例化后的变量一样长,所以显然是长于函数get的。所以引用返回是有效的。而且类似引用传入,少了拷贝的步骤,效率更高。当然本例中int本身不复杂,效率没啥区别。但若是一个相当复杂的结构体,那效率差别就大了。
当然引用返回最大的作用就在下面:

A a;
a.get(a) += 1; //这样是合法的。这就是引用返回的最大作用。可以对返回值直接做这样的操作。专业点的话就是,可以直接当作左值。这可是相当有用的。完全看不出傻在哪里~~~
说这样傻正说明LZ的不成熟吧。下面可以来个更具体的例子:

struct B

B();
int m_data[10];
int& operator [] (int i)return m_data[i];


void main()

B b;
b[0] = 1;
b[1] = 2; //怎么样,爽吧。


当然 若返回类型变为const &,就失去了左值的作用。但是省去拷贝,增加效率的作用还是在的
参考技术A const就是用来声明只读的,比较好理解,把const去掉不影响程序运行,只是影响程序可读性。
参数或返回里使用引用 本质是为了直接传入或返回对象本身,这样可以避免发生拷贝构造,某些情况返回对象本身可以让函数做左值
参考技术B const的作用是使变量的值不可改变 如果是指针变量 则该指针变量不能再指向其他对象
&是C++的写法 作为引用参数使用的
普通的变量A在传递给函数作为实参时, 是需要在该函数内部先复制一份A的副本, 之后对该变量的所有操作都是在副本上进行的, 与原来的变量A没有任何关系
但是使用&的变量A在传递给函数作为实参时,是直接把该变量A的地址传递给了形参变量, 意思就是此时形参变量和实参变量A是同一个变量, 对形参的任何操作就是对实参变量A的操作, 感觉和指针的用途是差不多的
函数返回值用&的情况我只见过一种 就是C++的流运算符<<和>>的重载, 书上说是为了级联操作, 就是可以像这样cout << A << B << ... << endl; 具体也没闹明白咋回事

在原始类型c ++中返回const或非常量有啥区别[重复]

【中文标题】在原始类型c ++中返回const或非常量有啥区别[重复]【英文标题】:what is the difference returning const or non-const in primative types c++ [duplicate]在原始类型c ++中返回const或非常量有什么区别[重复] 【发布时间】:2013-10-25 07:49:53 【问题描述】:

我试图了解如果我添加 const 或在返回函数时忽略它会有什么不同。让我通过一个例子来解释我的问题。

const int foo()

    return 3;


int main()

    int check;
    check=foo();
    cout<<"before:"<<check<<endl;
    check=1;
    cout<<"after:"<<check<<endl;
    return 0;   

到目前为止,我一直认为,由于我编写了 const foo(),我无法更改检查变量,但是我编译它并没有出错。

我想知道在我的 foo() 函数之前写 const 会得到什么或失去什么。

提前致谢

【问题讨论】:

曾经建议这样做,以避免意外分配给返回的临时:foo() = 10; // fails to compile。现在建议不要这样做,因为它禁止移动语义(即,这意味着您必须将整个返回的临时复制到某个局部变量中,而不是窃取它。并不是说它在原始情况下有所不同,而是作为一般规则很好)。在您的情况下,check 不是const,并且被赋予与foo 临时返回的const 相同的 ***.com/questions/10177904/… 可能重复 对于“可能”的相当严格的定义 - 这完全是一个骗局。 【参考方案1】:

原始返回类型上的 const 修饰符将被忽略。

另请参阅此问题:Should I return const objects?

【讨论】:

【参考方案2】:

您没有更改变量。您正在更改它的副本。

check=foo();

foo 返回的值分配给checkcheck 不是 const

【讨论】:

【参考方案3】:

不同之处在于编译器警告:

warning: type qualifiers ignored on function return type [-Wignored-qualifiers]
const int foo()
              ^

见live demo。

这种东西被忽略了,所以没有效果。

【讨论】:

不同之处在于警告......非常糟糕的描述。你应该说为什么会抛出警告...... @Zaibis 如果您真的阅读了警告,它会告诉您原因。 所以无论如何你应该提一下发生这种情况的原因是什么。 @Zaibis 所以我应该解释一下为什么编译器遵循标准?原始类型的限定符被忽略。没有更多的了...... 不,但你可以补充说这是标准的一部分,或者只是说它必须是这样的,因为我敢打赌,有人问像 OP 这样的问题并不能确认符合标准,所以它会帮助一些人;)【参考方案4】:

当您尝试返回参考时会有所不同。

例如:

int gGlobal;

const int & func()

    return gGlobal;


int main ()

     //Following statement will give error.
     func() = 3;
     return 0;

【讨论】:

那是完全不同的事情。 @jrok:当然不是,他是对的。 @DídacPérez 他是对的,但这与 OP 问题无关。

以上是关于C++返回值为Const &的看法 大虾们给解释下的主要内容,如果未能解决你的问题,请参考以下文章

C++中vector+模板的使用方法有哪些?

在原始类型c ++中返回const或非常量有啥区别[重复]

为什么赋值操作符函数的参数为const引用,返回值为引用

C语言函数返回值为 const 型 有啥意义

c++问题,请大虾们指点!

c++中的uint是为了保证返回值为正数使用的么,还是在啥情况下使用