c++---vector介绍
·
先点赞后观看哦!!!谢谢大家!
1.vector的使用说明
1.1vector的介绍
http://www.cplusplus.com/reference/vector/vector/
使用
STL
的三个境界:能用,明理,能扩展 ,那么学习
vector
,我们也是按照这个方法去学
习。
1.2vector的使用
1.2.1vector的定义

1.2.2vector literator的使用


1.2.3vector空间增长问题

1.capacity
的代码在
vs
和
g++
下分别运行会发现,
vs
下
capacity
是按
1.5
倍增长的,
g++
是按
2
倍增长的
。这个问题经常会考察,不要固化的认为,
vector
增容都是
2
倍,具体增长多少是
根据具体的需求定义的。
vs
是
PJ
版本
STL
,
g++
是
SGI
版本
STL
。
2.reserve
只负责开辟空间,如果确定知道需要用多少空间,
reserve
可以缓解
vector
增容的代
价缺陷问题。
3.resize
在开空间的同时还会进行初始化,影响
size
。
//
如果已经确定
vector
中要存储元素大概个数,可以提前将空间设置足够
//
就可以避免边插入边扩容导致效率低下的问题了
void
TestVectorExpandOP
()
{
vector
<
int
>
v
;
size_t
sz
=
v
.
capacity
();
v
.
reserve
(
100
);
//
提前将容量设置好,可以避免一遍插入一遍扩容
cout
<<
"making bar grow:\n"
;
for
(
int
i
=
0
;
i
<
100
;
++
i
)
{
v
.
push_back
(
i
);
if
(
sz
!=
v
.
capacity
())
{
sz
=
v
.
capacity
();
cout
<<
"capacity changed: "
<<
sz
<<
'\n'
;
}
}
}
1.2.3vector增删改查

1.2.4vector迭代器失效问题(重点)
迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对
指针进行了封装
,比如:
vector
的迭代器就是原生态指针
T*
。因此
迭代器失效,实际就是迭代器
底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间
,造成的后果是程序崩溃
(
即
如果继续使用已经失效的迭代器,程序可能会崩溃
)
。
对于
vector
可能会导致其迭代器失效的操作有:
1.
会引起其底层空间改变的操作,都有可能是迭代器失效
,比如:
resize
、
reserve
、
insert
、
assign
、
push_back
等。
#include <iostream>
using namespace
std
;
#include <vector>
int
main
()
{
vector
<
int
>
v
{
1
,
2
,
3
,
4
,
5
,
6
};
auto
it
=
v
.
begin
();
// 将有效元素个数增加到
100
个,多出的位置使用
8
填充,操作期间底层会扩容
// v.resize(100, 8);
// reserve的作用就是改变扩容大小但不改变有效元素个数,操作期间可能会引起底层容
量改变
// v.reserve(100);
// 插入元素期间,可能会引起扩容,而导致原空间被释放
// v.insert(v.begin(), 0);
// v.push_back(8);
// 给
vector
重新赋值,可能会引起底层容量改变
v
.
assign
(
100
,
8
);
/*
出错原因:以上操作,都有可能会导致vector
扩容,也就是说
vector
底层原理旧空间被释
放掉,而在打印时,it
还使用的是释放之间的旧空间,在对
it迭代器操作时,实际操作的是
一块已经被释放的空间,而引起代码运行时崩溃。
解决方式:在以上操作完成之后,如果想要继续通过迭代器操作vector
中的元素,只需给
it重新赋值即可。
*/
while
(
it
!=
v
.
end
())
{
cout
<< *
it
<<
" "
;
++
it
;
}
cout
<<
endl
;
return
0
;
}
2.
指定位置元素的删除操作
-
-erase、
int
main
()
{
int
a
[]
=
{
1
,
2
,
3
,
4
};
vector
<
int
>
v
(
a
,
a
+
sizeof
(
a
)
/
sizeof
(
int
));
// 使用
find
查找
3
所在位置的
iterator
vector
<
int
>
::
iterator pos
=
find
(
v
.
begin
(),
v
.
end
(),
3
);
// 删除
pos
位置的数据,导致
pos
迭代器失效。
v
.
erase
(
pos
);
cout
<< *
pos
<<
endl
;
//
此处会导致非法访问
return
0
;
}
erase
删除
pos
位置元素后,
pos
位置之后的元素会往前搬移,没有导致底层空间的改变,理
论上讲迭代器不应该会失效,但是:如果
pos
刚好是最后一个元素,删完之后
pos
刚好是
end
的位置,而
end
位置是没有元素的,那么
pos
就失效了。因此删除
vector
中任意位置上元素
时,
vs
就认为该位置迭代器失效了。
以下代码的功能是删除
vector
中所有的偶数,请问那个代码是正确的,为什么?
int
main
()
{
vector
<
int
>
v
{
1
,
2
,
3
,
4
};
auto
it
=
v
.
begin
();
while
(
it
!=
v
.
end
())
{
if
(
*
it
%
2
==
0
)
v
.
erase
(
it
);
++
it
;
}
return
0
;
}
int
main
()
{
vector
<
int
>
v
{
1
,
2
,
3
,
4
};
auto
it
=
v
.
begin
();
while
(
it
!=
v
.
end
())
{
if
(
*
it
%
2
==
0
)
it
=
v
.
erase
(
it
);
else
++
it
;
}
return
0
;
}
3.
注意:
Linux
下,
g++
编译器对迭代器失效的检测并不是非常严格,处理也没有
vs
下极端。
// 1.
扩容之后,迭代器已经失效了,程序虽然可以运行,但是运行结果已经不对了
int
main
()
{
vector
<
int
>
v
{
1
,
2
,
3
,
4
,
5
};
for
(
size_t
i
=
0
;
i
<
v
.
size
();
++
i
)
cout
<<
v
[
i
]
<<
" "
;
cout
<<
endl
;
auto
it
=
v
.
begin
();
cout
<<
"
扩容之前,
vector
的容量为
: "
<<
v
.
capacity
()
<<
endl
;
// 通过
reserve
将底层空间设置为
100
,目的是为了让
vector
的迭代器失效
v
.
reserve
(
100
);
cout
<<
"
扩容之后,
vector
的容量为
: "
<<
v
.
capacity
()
<<
endl
;
// 经过上述
reserve
之后,
it
迭代器肯定会失效,在
vs
下程序就直接崩溃了,但是
linux
下不会
// 虽然可能运行,但是输出的结果是不对的
while
(
it
!=
v
.
end
())
{
cout
<< *
it
<<
" "
;
++
it
;
}
cout
<<
endl
;
return
0
;
}
程序输出:
1 2 3 4 5
扩容之前,
vector
的容量为
:
5
扩容之后,
vector
的容量为
:
100
0 2 3 4 5 409 1 2 3 4 5
// 2. erase
删除任意位置代码后,
linux
下迭代器并没有失效
//
因为空间还是原来的空间,后序元素往前搬移了,
it
的位置还是有效的
#include <vector>
#include <algorithm>
int
main
()
{
vector
<
int
>
v
{
1
,
2
,
3
,
4
,
5
};
vector
<
int
>
::
iterator it
=
find
(
v
.
begin
(),
v
.
end
(),
3
);
v
.
erase
(
it
);
cout
<< *
it
<<
endl
;
while
(
it
!=
v
.
end
())
{
cout
<< *
it
<<
" "
;
++
it
;
}
cout
<<
endl
;
return
0
;
}
程序可以正常运行,并打印:
4
4 5
// 3: erase
删除的迭代器如果是最后一个元素,删除之后
it
已经超过
end
//
此时迭代器是无效的,
++it
导致程序崩溃
int
main
()
{
vector
<
int
>
v
{
1
,
2
,
3
,
4
,
5
};
// vector<int> v{1,2,3,4,5,6};
auto
it
=
v
.
begin
();
while
(
it
!=
v
.
end
())
{
if
(
*
it
%
2
==
0
)
v
.
erase
(
it
);
++
it
;
}
for
(
auto
e
:
v
)
cout
<<
e
<<
" "
;
cout
<<
endl
;
return
0
;
}
========================================================
//
使用第一组数据时,程序可以运行
[
sly@VM
-
0
-
3
-
centos
20220114
]
$ g
++
testVector
.
cpp
-
std
=
c
++
11
[
sly@VM
-
0
-
3
-
centos
20220114
]
$
.
/
a
.
out
1 3 5
=========================================================
//
使用第二组数据时,程序最终会崩溃
[
sly@VM
-
0
-
3
-
centos
20220114
]
$ vim testVector
.
cpp
[
sly@VM
-
0
-
3
-
centos
20220114
]
$ g
++
testVector
.
cpp
-
std
=
c
++
11
[
sly@VM
-
0
-
3
-
centos
20220114
]
$
.
/
a
.
out
Segmentation fault
从上述三个例子中可以看到:
SGI STL
中,迭代器失效后,代码并不一定会崩溃,但是运行
结果肯定不对,如果
it
不在
begin
和
end
范围内,肯定会崩溃的。
4.
与
vector
类似,
string
在插入
+
扩容操作
+erase
之后,迭代器也会失效
#include <string>
void
TestString
()
{
string s
(
"hello"
);
auto
it
=
s
.
begin
();
// 放开之后代码会崩溃,因为
resize
到
20
会
string
会进行扩容
// 扩容之后,
it
指向之前旧空间已经被释放了,该迭代器就失效了
// 后序打印时,再访问
it
指向的空间程序就会崩溃
//s.resize(20, '!');
while
(
it
!=
s
.
end
())
{
cout
<< *
it
;
++
it
;
}
cout
<<
endl
;
it
=
s
.
begin
();
while
(
it
!=
s
.
end
())
{
it
=
s
.
erase
(
it
);
// 按照下面方式写,运行时程序会崩溃,因为
erase(it)
之后
// it位置的迭代器就失效了
// s.erase(it);
++
it
;
}
}
迭代器失效解决办法:在使用前,对迭代器重新赋值即可
。
2.vector深度刨析及模拟实现


2.1std::vector的框架接口的模拟实现zzh::vector
https://gitee.com/zhejiang-daniel-wu/my_c_code/blob/master/text_09_25/text_09_25/vector.h
2.2使用memcpy拷贝问题
假设模拟实现的
vector
中的
reserve
接口中,使用
memcpy
进行的拷贝,以下代码会发生什么问
题?
int
main
()
{
zzh::vector
<
bite::string
>
v
;
v
.
push_back
(
"1111"
);
v
.
push_back
(
"2222"
);
v
.
push_back
(
"3333"
);
return
0
;
}
问题分析:
1. memcpy
是内存的二进制格式拷贝,将一段内存空间中内容原封不动的拷贝到另外一段内存
空间中
2.
如果拷贝的是自定义类型的元素,
memcpy
既高效又不会出错,但如果拷贝的是自定义类型
元素,并且自定义类型元素中涉及到资源管理时,就会出错,因为
memcpy
的拷贝实际是浅
拷贝。

结论:如果对象中涉及到资源管理时,千万不能使用
memcpy
进行对象之间的拷贝,因为
memcpy
是浅拷贝,否则可能会引起内存泄漏甚至程序崩溃。
2.2动态二维数组理解
//
以杨慧三角的前
n
行为例:假设
n
为
5
void
test2vector
(
size_t
n
)
{
// 使用
vector
定义二维数组
vv
,
vv
中的每个元素都是
vector<int>
bit::vector
<
bit::vector
<
int
>>
vv
(
n
);
// 将二维数组每一行中的
vecotr<int>
中的元素全部设置为
1
for
(
size_t
i
=
0
;
i
<
n
;
++
i
)
vv
[
i
].
resize
(
i
+
1
,
1
);
// 给杨慧三角出第一列和对角线的所有元素赋值
for
(
int
i
=
2
;
i
<
n
;
++
i
)
{
for
(
int
j
=
1
;
j
<
i
;
++
j
)
{
vv
[
i
][
j
]
=
vv
[
i
-
1
][
j
]
+
vv
[
i
-
1
][
j
-
1
];
}
}
}
zzh::vector<bit::vector<int>> vv(n)
;
构造一个
vv
动态二维数组,
vv
中总共有
n
个元素,每个元素
都是
vector
类型的,每行没有包含任何元素,如果
n
为
5
时如下所示:
更多推荐


所有评论(0)