使用'auto'进行迭代时,'&'符号会起什么作用

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

for (auto it : con){
Run Code Online (Sandbox Code Playgroud)

具有不同内容的相同地址!

这对于具有自动存储持续时间的变量非常典型.这与autoC++ 无关.如果你曾经使用过,你会得到相同的结果int:

for (int it : con){
Run Code Online (Sandbox Code Playgroud)

it(以及循环中的每个自动变量)的生命周期只是一次迭代.由于it最后一次迭代的生命周期结束,下一次迭代可以重复使用相同的内存,这就是地址相同的原因.


Why does the '&' sign make a change under this circumstance?
Run Code Online (Sandbox Code Playgroud)

因为T&声明了对类型的引用T.引用变量与非引用(对象变量)不同.而不是保持诸如对象之类的值,而是引用"引用"另一个对象.

在引用上使用addressof运算符时,结果将是引用对象的地址; 不是引用的地址(甚至可能没有地址,因为它不是对象).这就是后一种情况下地址变化的原因.在这种情况下,引用将引用int存储在节点中的对象what(因为con它本身是引用,并且引用传递的对象).


†我在C++中提到过,因为在C auto中实际上是一个存储类修饰符,表示自动存储类.它从来没有在标准C++中具有那种意义,它的使用在C中也已经过时了.它是B语言的残留关键词.

在C++中,auto声明将从上下文推导出的类型.

  • 加上一个"非常典型"的事实,这个答案非常好. (4认同)

pqn*_*net 7

让我们先看看:循环语法的扩展版本.

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在第二个循环中修改它会影响容器中的项目

地址问题也可以用这种方式解释:在复制示例中,局部变量在每次循环迭代中始终具有相同的地址(因为它们的生命周期不重叠,编译器没有理由不在堆栈中使用相同的地址),如果你将函数内部的代码分解,你可能会观察到它在不同的函数调用中发生变化(因为堆栈大小可能不同),在参考示例中,地址每次都不同,因为获取引用的地址将产生地址被引用的对象(在这种情况下,容器中的项)


Bat*_*eba 6

请注意,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,因此它的地址将在每次迭代不同.