下面的代码工作正常,据我所知,每次调用该函数时,都会创建一个局部变量(即 vector ),并且所有权将在第一次调用时以右值引用和常量引用(如果我在第二次调用时删除它甚至不会编译)。结果,局部变量实际上并没有在函数终止时消失,而是在 main 中的引用超出范围时(即在 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;
}
输出:
gsamaras@pythagoras:~$ g++ -std=c++0x -Wall px.cpp
gsamaras@pythagoras:~$ ./a.out
1
2
3
1
2
3
但我认为局部变量在超出范围时就会消失,除非在它们之前有 static
关键字,或者它们已被动态分配,甚至被复制。在这种情况下, vector 不会被复制。也许我的 C 背景使我无法理解这里的概念。你能帮帮我吗?
作为旁注,第一种情况允许您修改 vector ,而第二种情况显然不会。猜猜第一个是 C++11 特性,而第二个是传统特性。
我刚刚用自定义类做了一个示例,复制构造函数不会被调用,但它会像上面的示例一样工作!
最佳答案
当你写 std::vector<int> &&rval_ref = get_v();
这些是 return v;
时的概念性步骤达到了
- 创建了一个称为返回值 的临时对象。该对象被初始化为
std::vector<int> x{v};
.它“生活”在main
中当main
中的此语句时,自然会“超出范围”已经完成了。 -
v
被摧毁 - 引用文献
rval_ref
绑定(bind)到该临时对象。将引用绑定(bind)到临时对象会导致对象的生命周期延长以匹配引用的生命周期。
“临时对象”这个名称有点用词不当,因为该对象实际上可能会持续很长时间,但这是正式名称。 “未命名对象”是另一种可能的描述。
您的引用资料未提及 v
,它们引用它的拷贝(因为您的函数按值返回)。所以即使v
被销毁,拷贝未被销毁。
由于复制省略,您的测试代码未显示复制构造函数调用(上述第 1 步)。复制省略意味着编译器可能会选择为 v
使用相同的内存空间。因为它会用于返回值;并省略 v
的析构函数以及返回值的复制构造函数(即使这些函数有副作用)。
关于c++ - 右值引用的生命周期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32194231/