Shi*_*ang 3 c++ for-loop reference auto c++11
最近我在C++中使用auto时遇到了非常奇怪的问题,只是...看看下面的代码片段:
我的主要功能:
#include <list>
#include <iostream>
#include <stdio.h>
int main(){
int a = 10, b = 20, c = 30;
list<int> what;
what.push_back(a);
what.push_back(b);
what.push_back(c);
read(what);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这里的功能如下:
void read(const list<int>& con){
for (auto it : con){
printf("%p\n", &it);
cout << it << endl;
}
return ;
}
Run Code Online (Sandbox Code Playgroud)
这是输出:
0x7fffefff66a4
10
0x7fffefff66a4
20
0x7fffefff66a4
30
Run Code Online (Sandbox Code Playgroud)
那是什么呀?具有不同内容的相同地址!
更奇怪的是,如果我通过添加'&'
来修改for循环,那么:
for (auto& it : con){
Run Code Online (Sandbox Code Playgroud)
所有输出立即有意义,地址将通过迭代改变
所以我的问题是,
为什么'&'标志在这种情况下会发生变化?
eer*_*ika 20
Run Code Online (Sandbox Code Playgroud)for (auto it : con){具有不同内容的相同地址!
这对于具有自动存储持续时间的变量非常典型.这与autoC++ †无关.如果你曾经使用过,你会得到相同的结果int:
for (int it : con){
Run Code Online (Sandbox Code Playgroud)
it(以及循环中的每个自动变量)的生命周期只是一次迭代.由于it最后一次迭代的生命周期结束,下一次迭代可以重复使用相同的内存,这就是地址相同的原因.
Run Code Online (Sandbox Code Playgroud)Why does the '&' sign make a change under this circumstance?
因为T&声明了对类型的引用T.引用变量与非引用(对象变量)不同.而不是保持诸如对象之类的值,而是引用"引用"另一个对象.
在引用上使用addressof运算符时,结果将是引用对象的地址; 不是引用的地址(甚至可能没有地址,因为它不是对象).这就是后一种情况下地址变化的原因.在这种情况下,引用将引用int存储在节点中的对象what(因为con它本身是引用,并且引用传递的对象).
†我在C++中提到过,因为在C auto中实际上是一个存储类修饰符,表示自动存储类.它从来没有在标准C++中具有那种意义,它的使用在C中也已经过时了.它是B语言的残留关键词.
在C++中,auto声明将从上下文推导出的类型.
让我们先看看:循环语法的扩展版本.
for( auto it: container) {
...
}
Run Code Online (Sandbox Code Playgroud)
在概念上是相同的
for( auto _it = container.begin(); _it != container.end(); it++) {
auto it = *_it;
...
}
Run Code Online (Sandbox Code Playgroud)
而参考表格:
for( auto& it: container)
Run Code Online (Sandbox Code Playgroud)
是相同的
for( auto _it = container.begin(); _it != container.end(); it++) {
auto &it = *_it;
...
}
Run Code Online (Sandbox Code Playgroud)
所以在第一种情况下it是容器中项目的副本,在第二种情况下它是它的(左值)引用,因此如果你it在第二个循环中修改它会影响容器中的项目
地址问题也可以用这种方式解释:在复制示例中,局部变量在每次循环迭代中始终具有相同的地址(因为它们的生命周期不重叠,编译器没有理由不在堆栈中使用相同的地址),如果你将函数内部的代码分解,你可能会观察到它在不同的函数调用中发生变化(因为堆栈大小可能不同),在参考示例中,地址每次都不同,因为获取引用的地址将产生地址被引用的对象(在这种情况下,容器中的项)
请注意,auto是站在了int你的情况.所以这是一个红鲱鱼.考虑
for (int i = 0; i < 10; ++i){
int j = i;
cout << (void*)&j << '\n';
}
Run Code Online (Sandbox Code Playgroud)
由于j具有自动存储持续时间,因此很可能每次都使用相同的地址创建 - 但指向不同的值 - j正在被推送,然后在每次迭代时从堆栈中弹出(让我们留出编译器优化).这就是你的情况for (auto it : con){.it有自动存储时间.
当你写作
for (auto& it : con){
Run Code Online (Sandbox Code Playgroud)
it是一个参考到int在容器内con,因此它的地址将在每次迭代不同.