C++ 右值ref的生存期
下面的代码运行良好,据我所知,每次调用函数时,都会创建一个局部变量(即vector),并且在第一次调用时,所有权将在右值引用中转移,在第二次调用时,所有权将在常量引用中转移(如果我删除了它,它甚至不会编译)。因此,当函数终止时,局部变量实际上并没有消失,而是当main中的引用超出范围时(即在C++ 右值ref的生存期,c++,c++11,scope,rvalue-reference,rvalue,C++,C++11,Scope,Rvalue Reference,Rvalue,下面的代码运行良好,据我所知,每次调用函数时,都会创建一个局部变量(即vector),并且在第一次调用时,所有权将在右值引用中转移,在第二次调用时,所有权将在常量引用中转移(如果我删除了它,它甚至不会编译)。因此,当函数终止时,局部变量实际上并没有消失,而是当main中的引用超出范围时(即在main()的末尾),我认为 #include <iostream> #include <vector> std::vector<int> get_v(void) {
main()
的末尾),我认为
#include <iostream>
#include <vector>
std::vector<int> get_v(void)
{
std::vector<int> v{1,2,3};
return v;
}
int main() {
std::vector<int> &&rval_ref = get_v();
for(unsigned int i = 0; i < rval_ref.size(); ++i)
std::cout << rval_ref[i] << "\n";
const std::vector<int> &con_ref = get_v();
for(unsigned int i = 0; i < con_ref.size(); ++i)
std::cout << con_ref[i] << "\n";
return 0;
}
但我认为局部变量在超出范围时会消亡,除非它们前面有一个static
关键字,或者它们被动态分配,甚至被复制。在这种情况下,不复制向量。也许我的C语言背景使我无法理解这里的概念。你能帮我吗
作为旁注,第一种情况允许您修改向量,而第二种情况显然不允许。我猜第一个是C++11特性,而第二个是传统特性
我刚刚用一个自定义类做了一个示例,复制构造函数将不会被调用,但它将与上面的示例一样工作 您的
get\u v
函数返回一个值,因此v
超出范围并不重要,因为您返回了它的值
这与:
int a()
{
int j = 3;
return j; // returns the *value* of j
}
C++标准允许编译器通过某种方式将代码构造函数逐出代码,将代码> V>代码>调用。C++标准还需要在引用绑定到它时延长临时的生存期。
当编写“代码> STD::vector and rValueRe= GETYVE())时,<这些是返回v时的概念步骤代码>已到达
将创建一个称为返回值的临时对象。这个对象被初始化,就像是通过std::vector x{v}代码>。它“存在”于main
中,当main
中的此语句完成时,它自然会“超出范围”
v
被销毁
参考rval\u ref
绑定到该临时对象。将引用绑定到临时对象会导致对象的生存期延长,以匹配引用的生存期
“临时物体”这个名字有点用词不当,因为这个物体实际上可能会持续很长时间,但这是官方名称。“未命名对象”是另一种可能的描述
您的引用并不是指v
,而是指它的副本(因为您的函数是按值返回的)。因此,即使v
被销毁,副本也不会被销毁
由于复制省略,测试代码没有显示复制构造函数调用(上面的步骤1)。复制省略意味着编译器可以选择使用与返回值相同的v
内存空间;并省略v
的析构函数和返回值的复制构造函数(即使这些函数有副作用)。get\u v
通过值而不是引用返回。因此,复制构造函数将被称为@captainobvious?一个朋友告诉我不会的!该副本可能会被省略,但可能不会。这取决于优化。无论哪种方式,您仍在按值返回,因此将创建属于调用方的向量的唯一实例。@CaptainObvlious这对我来说仍然不明显,抱歉!也检查我的编辑。我无法理解这是如何发生的。您返回的副本将成为临时(未命名)对象。你的常量&
然后绑定到未命名的临时文件,给它起一个名字(从而延长它的寿命)。哦,转发它是这里的关键。请你对此进行一点扩展(我非常感谢你给我一些简单的话)或者提供一个解释性的链接?请看维基百科上的和。谢谢大卫。从这里的例子中,我了解到转发与RVO有关(是同一件事吗?我想不是…)。因此,在这种情况下,编译器足够聪明,不会破坏局部变量,而是通过在main()
中为其指定变量名来“重命名”它?我不知道你为什么把我和副本ε联系起来。@gsamaras是对的。看来你明白了。是的,到RVO的链接是错误的。@gsamaras Copy-elision是标准在提到省略的拷贝和移动时使用的,RVO是一种拷贝省略的非正式名称。在抛出和捕获时,以及在复制未绑定的临时对象时(通常发生在RVO之后),也可能发生复制省略。
int a()
{
int j = 3;
return j; // returns the *value* of j
}