for(auto &i:s)和for(auto i:s)的区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
有道题是这样的,n组数据,进行如下操作
1 x y; 1表示插入,x整数,y表示所属类型(类型已存在,插入该类型末尾;不存在,插入新类型第一位)
2 x y; 2表示交换x系列与y系列的位置
输出最终结果

示例:
7
1 1 a
1 2 b
1 5 a
1 3 c
1 4 d
2 a b
2 b c
结果:
3 1 5 2 4

思路:list存储结构体(包含类型与节点),上述插入、交换操作就变成了对链表的操作。若数据量大,vector<int> node; 改完 list<int> node;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include <iostream>
#include <string>
#include <vector>
#include <list>

using namespace std;

struct train {
string type;
vector<int> node;
};

int main() {
int n;
cin >> n;

vector<train> rs;
while (n--) {
int choose;
cin >> choose;
bool isE = false;

switch (choose)
{
case(1): {
int id;
string node_type;
cin >> id >> node_type;
//注意这里:
//for (auto it : rs) {
for (auto &it : rs) {
if (it.type == node_type) {
it.node.push_back(id);
cout<<id << node_type << "插入" << it.type << ' ' << it.node.size()<<endl;
isE = true;
break;
}
}
//使用迭代器
//for (vector<train>::iterator it = rs.begin(); it != rs.end(); it++ ) {
// if (it->type == node_type) {
// it->node.push_back(id);
// //cout << endl <<id << node_type << "插入" << it->type << ' ' << it->node.size()<<endl;
// isE = true;
// break;
// }
//}

//新系列
if (!isE) {
train temp;
temp.type = node_type;
temp.node.push_back(id);
rs.push_back(temp);
}

break;
}
case(2): {
string switch_a, switch_b;
cin >> switch_a >> switch_b;

int len = rs.size();
int i = len + 1, j = len + 1;

for (int k = 0; k < len; k++) {
if (rs[k].type == switch_a) {
i = k;
}
if (rs[k].type == switch_b) {
j = k;
}
}

//交换合法
if (i < len && j < len) {
train temp = rs[i];
rs[i] = rs[j];
rs[j] = temp;

}
break;
}
default:
break;
}


//cout << endl << "-------------第" << n << endl ;
//for (auto it : rs) {
// //cout<< "节点数量 "<< it.node.size() << endl;
// for (auto i : it.node) {
// cout << i << " ";
// }
//}
//cout << endl << "-------------" << endl << endl;
}


//输出结果
for (auto it : rs) {
for(auto i : it.node){
cout << i << " ";
}
}

return 0;
}

此时出现了一个小问题:

for(auto i:s)

image-20210419144958282

for(auto &i:s)

image-20210419145120107

这个bug产生的原因是什么呢?

参考《C++prime》与C++ auto类型说明符如for(atuo &x : s)

如果要更改字符串中的字符值,我们必须将循环变量定义为引用类型。当我们使用引用(别名)作为我们的控制变量时,该变量依次绑定到序列中的每个元素。使用引用,我们可以更改引用所绑定的字符。for循环中的每个迭代初始化一个新的引用。

for(auto i:s)会拷贝一份s中的元素,而不会改变s中元素; 特例:使用for(auto x:vector<bool>)时得到一个proxy class,操作时会改变vector<bool>本身元素。

for(auto &i:s):s中的元素的别名,可修改元素值;特例:当vector<bool>返回临时对象,使用auto&会编译错误,临时对象不能绑在non-const l-value reference (左值引用),需使用auto&&,初始化右值时也可捕获(右值引用)

总结:

如果只是访问容器,for(auto i:s)for(auto &i:s)作用类似;

但是访问的同时进行改变其值,那就for(auto &i:s)没得跑,或者选用迭代器;

想要只读元素:for(const auto& i:s) 不会像for(auto i:s)一样产生拷贝开销,也不会像for(auto &i:s)改变元素值。

ps:回顾 auto(自动类型推断) 、static、new

auto 的对应类型(既不是new 出来,也不是static变量),它只是该作用域(可能是函数体内、for内)定义的局部变量。C++中auto定义的变量必须初始化(因编译器推断变量或表达式的类型),而C中auto关键字修饰的变量默认为int 型数据

static 变量(无论全局还是局部)是程序结束的时候才释放对象的,但它不需要手动释放,保存在全局区。
(1)static 如果在一个函数内申明,这每次进入这个函数时,还是使用第一次声明的变量,并且还保存的上次使用的值【用于“记忆化”】。
(2)static 变量如果在结构和类中使用,这结构或类定义的一切对象,都将共享唯一 static 变量(所以需要类外初始化)。

new创建存储在堆区的变量,必须手动释放(delete),避免内存泄漏。

---------------- 本文结束 ----------------

本文标题:for(auto &i:s)和for(auto i:s)的区别

文章作者:Pabebe

发布时间:2021年04月19日 - 14:19:38

最后更新:2021年04月19日 - 16:01:18

原始链接:https://pabebezz.github.io/article/4aa05e8/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

0%