Container¶
Abstraction
- Referennce
- STL Containers
- vector
- list
- map
- STL Iterator
Declaring References¶
char c; // a character
char *p = &c; // a pointer to a character
char &r = c; // a reference to a character
*, &
可以是标点,也可以是运算符,如 &
在第二行是一个运算符,在第三行是一个标点。
当我们声明引用时,必须有引用的变量。此后,r 相当于是 c 的一个别名。
Example
此时我们发现两行的输出都是 B.- Local or global variables
type& refname = name;
- For ordinary variables, the initial value is required.
- In parameter lists and member variables
type& refname
- Binding defined by caller or constructor
函数只有在调用时,参数才能绑定。
这样可以实现函数对函数外变量的值的修改。
const int& z = x;
这里的 const
是对引用的限制,表示我们不能写 z, 但 x 依然是可写的。
void f(int &x)
{
x++;
}
int main()
{
int a = 51;
cout << "a=" << a << endl;
f(a);
cout << "a=" << a << endl;
}
The target of a reference must have a location!
即右值不能用于引用绑定。
Pointers vs. References
- References
- can't be null
- are dependent on an existing variable, they are an alias for an variable
- can't change to a new "address" location
- Pointers
- can be set to null
- pointer is independent of existing objects
- can change to point to a different address
实际上, C++ 内部实现引用也是通过指针,只是限制这个指针只能指向初始化的变量。
Restrictions
- No references to references
- No pointers to references
- Reference to pointer is ok
- No arrays of references
Container¶
Collection objects are objects that can store an arbitrary number of other objects.
在 C++ 中,容器在 STL 中。
- STL = Standard Template Library
- Part of the ISO Standard C++ Library
- Data Structures and algorithms for C++.
Why should I use STL?
- Reduce development time.
Data-structures already written and debugged. - Code readability
- Fit more meaningful stuff on one page.
- Robustness
STL data structures grow automatically. - Portable code.
- Maintainable code
- Easy
Library includes
- A
pair
class (pairs of anything, int/int, int/char, etc) - containers
vector
(expandable array)deque
(expandable array, expands at both ends)list
(double-linked)sets
andmaps
- Basic Algorithms (
sort
,search
, etc)
All identifiers in library are in std namespace: using namespace std;
Vector¶
每个容器是一个头文件,需要 include. 如 #include<vector>
.
#include <iostream>
#include <vector>
using namespace std;
int main( ) {
// Declare a vector of ints (no need to worry about size)
vector<int> x;
// Add elements
for (int a=0; a<1000; a++)
x.push_back(a);
// Have a pre-defined iterator for vector class, can use it to print out the items in vector
vector<int>::iterator p;
for (p=x.begin(); p<x.end(); p++)
cout << *p << " ";
return 0;
}
- 这是泛型定义 (generic classes),我们需要指定
vector
和vector
内的元素类型。(vector<int> x
) vector<int>::iterator
是一个类型。实际上 p 不是一个指针,这里利用了 C++ 的运算符重载。
今天有语法糖(C++11)
auto
的意思是类型自动推断。这里会从 x
中依次取出一个值,随后放到 i
里去。
vector
- It is able to increase its internal capacity as required: as more items are added, it simply makes enough room for them.
- It keeps its own private count of how many items it is currently storing. Its size method returns the number of objects currently stored in it.
- It maintains the order of items you insert into it. You can later retrieve them in the same order.
Basic Vector Operations¶
- Constructor
vector<Elem>c;
vector<Elem>c1(c2);
- Simple Methods
V.size(); // num items
V.empty(); // empty?
==, !=, <, >, <=, >=
V.swap(v2); // swap
- Iterators
I.begin() // first position
I.end() // last position
- Element access
V.at(index)
V[index]
V.front() // first item
V.back() // last item
- Add/Remove/Find
V.push_back(e)
V.pop_back()
V.insert(pos, e)
V.erase(pos)
V.clear()
V.find(first, last, item)
Two ways to use vector
可以预先分配,但增长只能用 push_back
.
List Class¶
Same basic concepts as vector
- Constructors
- Ability to compare lists
(==, !=, < , <=, > , >=)
- Ability to access front and back of list
Sample List Application
#include <iostream>
#include <list>
#include <string>
using namespace std;
int main()
{
list<string>s;
s.push_back("hello");
s.push_back("world");
s.push_front("tide");
s.push_front("crimson");
s.push_front("alabama");
list<string>iterator:: p;
for (p=s.begin(); p!=s.end(); p++)
cout << *p << " ";
cout << endl;
}
p!=s.end()
因为列表每个空间是动态分配的,后申请的空间不能保证在先申请的空间后面。对 vector
来说空间是连续的。
Example
Maps¶
- Maps are collections that contain pairs of values.
- Pairs consist of a key and a value.
- Lookup works by supplying a key, and retrieving a value.
#include <map>
map<long,int> root;
root[4] = 2;
root[1000000] = 1000;
long l;
cin >> l;
if (root.count(l))
cout<<root[l]
else cout<<“Not perfect square”;
Iterators¶
- Declaring
list<int>::iterator li;
- Front of container
list<int>L;li = L.begin();
- Past the end
li = L.end();
- Can increment
- Can be dereferenced
*li = 10;
for-each loop¶
A for-each loop iterates over the elements of arrays, vectors, or any other data sets. It assigns the value of the current element to the variable iterator declared inside the loop.
Example
#include<iostream>
using namespace std;
int main()
{
int arr[]={1,2,3,4,5}; //array initialization
cout<<"The elements are: ";
for(int i : arr) // auto
{
cout<<i<<" ";
}
return 0;
}
auto
自动推断。
- 写起来简单,不需要预先初始化迭代器。
- 缺点是不能获得下标,也不能逆序遍历,也不能跳过某个单元,不能修改容器的值。
如果觉得名字很长,可以用 typedef
. e.g. typedef PB map<Name,list<PhoneNum> >;
Warning
The type in containers
v1.push_back(x)
会拷贝 x, 拷贝后 vector
里最后一个元素的值和 x 相同,但二者没有关系。v2.push_back(x)
会生成一个 x 的引用。
实际上这个循环中 s 作为本地变量,地址是不变的,如果我们采取后面两种定义 vector
的方法,最后 vector
中每个元素都是一样的。后面两种定义方法内存开销小,但易出错。
Pitfalls
- Accessing an invalid
Solutions- use
push_back()
- Preallocate with constructor.
- Reallocate with
reserve()
- Check
capacity()
- use
- Inadvertently inserting into
map<>
Solutions: Usecount()
to check for a key without creating a new entry.if ( foo.count("bob") )
- DO not use empty() on
list<>
- Use invalid iterator