我需要一些关于常量引用的澄清。this link:
const Foo &myFoo = FuncBar();
const引用延长了本地对象的寿命。但是当我检查this link时,尽管它们使用了const引用
Sandbox(const string& n) : member(n) {}
串“four”的寿命没有增加。
Sandbox sandbox(string("four"));
他们用了这个句子
只有局部常量引用才能延长寿命。
那么在第二个链接中,字符串“four”不是主函数的本地字符串吗?常量引用n
不应该延长它的寿命吗?
那么,为什么第二个环节的寿命没有延长呢?
2条答案
按热度按时间rdlzhqv91#
您所引用的两个链接在某种意义上是不同的,一个显示了局部const引用的使用,另一个显示了类成员const引用的使用。
当我们创建局部const引用并引用临时对象时,在这个编译器中,将临时对象的寿命延长到局部const引用的范围。
指向临时对象的类成员常量引用将导致意外的结果,因为临时对象的寿命将不会延长到被调用以初始化类成员引用的构造函数之外。正如在其中一个答案中所解释的那样,临时的将只存活到构造函数完成为止。
引用以下的答案:Does a const reference prolong the life of a temporary?
生存期延长不能通过函数参数传递。§12.2/5 [临时类]:
第二个上下文是当引用绑定到临时。引用绑定到的临时对象或临时对象是绑定到的子对象的完整对象的临时对象,除非下面指定的情况。在构造函数的ctor-initializer(§12.6.2 [class.base.init])中,临时绑定到引用成员,直到构造函数退出。在函数调用中,临时绑定到引用参数(§5.2.2 [expr.call])将持续到包含该调用的完整表达式完成。
如果你正确地分析它,你会意识到在这两种情况下,临时变量的寿命都被延长到引用被初始化的作用域有效为止。一旦引用的作用域超出作用域,临时性就失效了。
对于局部常量引用,作用域是在一个函数内部,从那里它被初始化为一个临时值。对于类成员const引用,作用域是构造函数,在构造函数中,作用域被初始化为临时变量。
你也应该阅读这篇GOTW文章:https://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/
taor4pac2#
我觉得有必要想象一下(在汇编/机器语言中)在幕后发生了什么,以帮助理解这种行为。
参数(值或值的地址)被传递到堆栈上的函数中。
当函数运行时,局部变量被推送到堆栈上,涉及这些变量的操作是使用一个相对于一个寄存器的地址完成的,该寄存器在调用函数时获得了堆栈指针(指向的地址)的值的副本。
当一个函数退出时,它“展开堆栈”,通过将堆栈指针移回它在参数被推入堆栈之前的位置,然后返回值被推入堆栈。
所以当我们调用一个函数时,我们的局部变量在堆栈上,我们的参数在它们之后被推送到堆栈上。当函数返回时,返回值在堆栈上,代替我们的参数,就在我们的局部变量之后。
如果我们将返回值赋给一个局部变量,编译器可能会选择以“复制省略”的形式进行一些“返回值优化”,方法是简单地将堆栈位置与该局部变量相关联。
在返回值被分配给“const引用”的情况下,这种“复制省略”可能是某种“强制的”或至少是“请求的”。但它仍然是对堆栈位置的引用--所以当调用函数的函数返回时……堆栈被展开,并且包括该返回值在内的所有局部变量都丢失。
鉴于此。直觉地想象理解发生了什么,似乎C++应该允许将局部非常量引用赋给返回值,但不应该允许非局部引用(const或其他)被分配给返回值,因为分配非局部引用意味着与该引用相关联的存储器以某种方式被保留在局部范围之外而不复制它,这在返回值存储在堆栈上的情况下,是相当不切实际的。