A gentle introduction to the standard template library (STL) - PowerPoint PPT Presentation

About This Presentation
Title:

A gentle introduction to the standard template library (STL)

Description:

iterators - iterate through a container's elements ... map (usually a binary tree), multimap, set, multiset. But there are no hash tables (sorry... – PowerPoint PPT presentation

Number of Views:104
Avg rating:3.0/5.0
Slides: 38
Provided by: hawb3
Category:

less

Transcript and Presenter's Notes

Title: A gentle introduction to the standard template library (STL)


1
A gentle introduction to the standard template
library (STL)
  • Some references
  • http//www-leland.stanford.edu/iburrell/cpp/stl.h
    tml
  • http//www.cs.rpi.edu/musser/stl.html
  • http//www.sgi.com/Technology/STL/ (this is so
    comprehensive that it documents things that
    arent even part of STL yet)

2
STL Organization
  • containers - hold collections of objects
  • iterators - iterate through a containers
    elements
  • algorithms - use iterators to implement sort,
    search, etc.

3
Where the STL code is located
  • Containers
  • include ltlistgt
  • include ltvectorgt
  • include ltmapgt
  • Plus more deque, queue, stack, set, bitset
  • Iterators (although you dont need to include
    this explicitly to use iterators)
  • include ltiteratorgt
  • Algorithms
  • include ltalgorithmgt
  • Utilities
  • include ltutilitygt
  • include ltfunctionalgt

4
  • STL was adopted in 1994 (fairly recently), so
    your compiler may not support it yet.
  • See http//www.cyberport.com/tangent/programming/
    stl/compatibility.html
  • for a list of compatible compilers.
  • Try the following
  • include ltvectorgt
  • include ltlistgt
  • using namespace std // may or may not be
    necessary
  • ...

5
Containers
  • Sequences
  • basic sequences vector, list
  • more exotic sequences deque, queue, stack,
    priority_queue
  • Associative containers
  • map (usually a binary tree), multimap, set,
    multiset
  • But there are no hash tables (sorry...)

6
  • vector usually implemented as a pointer to an
    array
  • pro implements fast indexing (looking up the nth
    element can be done in constant time)
  • con inserting elements into the middle of an
    array requires copying many elements to make room
    for the new element
  • list usually implemented as doubly linked lists
  • pro easy to insert and remove elements from
    middle of list (just rearrange pointers, no
    copying needed)
  • con indexing is slow (finding the nth element
    requires scanning through the list)

7
common vector, list constructors
  • vectorltfloatgt v1 // create an empty vector of
    floats
  • vectorltfloatgt v2(10, 5.0) // create a vector
    that
  • // initially holds 10
    floats,
  • // each initialized to
    5.0
  • listltfloatgt l // create an empty list of floats

8
Adding elements to vectors, lists
  • Elements can be appended to the back of a vector
    with push_back
  • vectorltfloatgt v1
  • v1.push_back(6.0)
  • v1.push_back(7.0)
  • v1.push_back(8.0)
  • Now v1 contains 3 elements 6.0, 7.0, 8.0
  • Note that the vector is automatically resized so
    that each new element added with push_back will
    fit (yay!).

9
  • The first and last elements of vectors and lists
    can be retrieved with the front() and back()
    member functions
  • vectorltfloatgt v1
  • v1.push_back(6.01)
  • v1.push_back(7.01)
  • v1.push_back(8.01)
  • v1.push_back(9.01)
  • float fFront v1.front()
  • float fBack v1.back()
  • cout ltlt fFront ltlt " " ltlt fBack ltlt endl
  • This prints
  • 6.01 9.01

10
  • pop_back() removes the last element from the
    vector
  • vectorltfloatgt v1
  • v1.push_back(6.01)
  • v1.push_back(7.01)
  • v1.push_back(8.01)
  • v1.push_back(9.01)
  • v1.pop_back()
  • cout ltlt v1.front() ltlt " " ltlt v1.back() ltlt endl
  • This prints
  • 6.01 8.01

11
  • lists support push_front and pop_front (to insert
    and remove elements at the front of a list), as
    well as push_back and pop_back
  • listltfloatgt l // create an empty list of floats
  • l.push_back(6.01)
  • l.push_back(7.01)
  • l.push_back(8.01)
  • l.push_front(9.01)
  • l.pop_back()
  • cout ltlt l.front() ltlt " " ltlt l.back() ltlt endl
  • This prints
  • 9.01 7.01

12
  • vectors support random access with and at().
    performs random access with no bounds
    checking, while at() performs bounds checking,
    and throws an out_of_range exception if the index
    is out of bounds
  • vectorltfloatgt v2(10, 5.0) // v2 has 10 elements
  • v23 5.0
  • v214 6.0 // XXX out of bounds! memory
    corruption!
  • v2.at(14) 6.0 // out of bounds, throws an
    exception
  • cout ltlt v2.at(3) ltlt endl
  • Warning and at() do not resize the vector if
    an index is out of bounds! If you need to
    increase the size of the vector, use push_back to
    add elements.

13
  • Both vectors and lists also support
  • size() returns the number of elements in the
    container
  • empty() returns true if size()0, and false
    otherwise

14
  • Summary of functions covered so far
  • vector list
  • ----------------------------------------
  • vector() list()
  • vector(size, init_val)
  • push_back push_back
  • push_front
  • pop_back pop_back
  • pop_front
  • front front
  • back back
  • at
  • size size
  • empty empty

15
  • So a hypothetical, simplified, definition of
    vector might look like
  • template ltclass Tgt class vector
  • public
  • vector()
  • vector(int n, const T val)
  • void push_back(const T x)
  • void pop_back()
  • T front()
  • T back()
  • T operator (int n)
  • T at(int n)
  • int size() const
  • bool empty() const
  • A simplified list class would look similar.

16
  • template ltclass Tgt class vector
  • public
  • vector()
  • vector(int n, const T val)
  • vector(const vectorltTgt x)
  • vector()
  • vectorltTgt operator (const vectorltTgt x)
  • ...
  • Of course, vector will have a copy constructor,
    assignment operator, and destructor. The copy
    constructor and assignment operator for STL
    container classes make copies of the entire
    container. This can be expensive, so if you
    dont want a copy, you should pass containers by
    reference
  • void foo(vectorltfloatgt v)
  • rather than by value
  • void foo(vectorltfloatgt v) // copies entire
    vector

17
  • Even if you never make copies of entire
    containers, your elements may be copied as they
    are inserted into the containers (and at other
    times).
  • So if the elements are classes with pointers,
    they should implement the correct copy
    constructor, assignment operator and destructor.

18
  • For classes that shouldnt be copied (such as
    large classes or classes with virtual functions),
    a container of pointers to objects can be used
  • vectorltShapegt shapes
  • Be aware that the container will not delete the
    pointed-to objects for you
  • vectorltShapegt shapes
  • shapes.push_back(new Circle())
  • shapes.pop_back() // memory leak the Circle
  • // was not deleted!
  • Correct
  • vectorltShapegt shapes
  • shapes.push_back(new Circle())
  • delete shapes.back()
  • shapes.pop_back()

19
  • For classes that arent copiable (such as large
    classes or classes with virtual functions), a
    container of pointers to objects can be used
  • vectorltShapegt shapes
  • Also note that containers of pointers to objects
    are copied by shallow copy, not deep copy
  • vectorltShapegt shapes1
  • shapes1.push_back(new Circle())
  • vectorltShapegt shapes2 shapes1 // make copy of
  • // entire
    vector
  • Now both shapes1 and shapes2 point to the same
    Circle object. Be careful not to delete this
    Circle object twice!

20
  • STL allows a containers memory management to be
    customized with user defined allocators
  • template ltclass T, class A allocatorltTgt gt class
  • vector
  • public
  • typedef typename Asize_type size_type
  • vector()
  • vector(size_type n, const T val)
  • vector(const vectorltTgt x)
  • vector()
  • vectorltTgt operator (const vectorltTgt x)
  • void push_back(const T x)
  • void pop_back()
  • T front()
  • T back()
  • T operator (size_type n)
  • T at(size_type n)
  • size_type size() const
  • bool empty() const

21
  • template ltclass T, class A allocatorltTgt gt class
    vector
  • public
  • typedef typename Asize_type size_type
  • vector()
  • vector(size_type n, const T val)
  • ...
  • For instance, an allocator might be written so
    that objects are stored in a large, persistent
    database. In this case, size_type might be
    larger than a normal int (it might be a 64-bit
    integer, for instance).
  • The allocatorltTgt specifies a default value
    for vectors allocator, which is used if you
    dont pass in an explicit allocator of your own.
    You probably will never have to worry about
    allocators explicitly chances are youll only
    need the default allocator.
  • However, if you have an old compiler that doesnt
    support default template values, you may have to
    pass in the default allocator explicitly (yuck)
  • vectorltfloat, allocatorltfloatgt gt v1(10, 5.0)

22
Iterators
  • vector list
  • ----------------------------------------
  • vector() list()
  • vector(size, init_val)
  • push_back push_back
  • push_front
  • pop_back pop_back
  • pop_front
  • front front
  • back back
  • at
  • size size
  • empty empty
  • You may have noticed that list had operations
    front() and back() to read the first and last
    elements, but how do you get to the rest of the
    elements?

23
  • Every container class defines one or more
    iterators that can be used to scan through the
    elements of the container
  • template ltclass T, class A allocatorltTgt gt class
    list
  • public
  • typedef typename Asize_type size_type
  • typedef ... iterator
  • typedef ... const_iterator
  • list()
  • list(const listltTgt x)
  • list()
  • listltTgt operator (const listltTgt x)
  • void push_back(const T x)
  • void push_front(const T x)
  • void pop_back()
  • void pop_front()
  • T front()
  • T back()
  • size_type size() const
  • bool empty() const

24
  • Example
  • listltfloatgt l
  • l.push_back(6.01)
  • l.push_back(7.01)
  • l.push_back(8.01)
  • l.push_back(9.01)
  • // Use a list iterator to iterate through l
  • listltfloatgtiterator i
  • for(i l.begin() i ! l.end() i)
  • cout ltlt i ltlt " "
  • This prints
  • 6.01 7.01 8.01 9.01

25
  • listltfloatgtiterator i
  • for(i l.begin() i ! l.end() i)
  • cout ltlt i ltlt " "
  • listltfloatgtiterator refers to the iterator
    defined in the class list
  • template ltclass T, class A allocatorltTgt gt class
    list
  • public
  • typedef typename Asize_type size_type
  • typedef ... iterator
  • typedef ... const_iterator
  • list()
  • ...

26
  • listltfloatgtiterator i
  • for(i l.begin() i ! l.end() i)
  • cout ltlt i ltlt " "
  • A list iterator supports several operations
  • The dereference operator () returns the element
    pointed to by the iterator
  • advances the iterator to the next element
  • ! compares the iterator with another iterator
    to see if the end of the list has been reached
  • template ltclass T, class A allocatorltTgt gt class
    list
  • public
  • typedef typename Asize_type size_type
  • typedef ... iterator
  • typedef ... const_iterator
  • list()
  • ...

27
  • listltfloatgtiterator i
  • for(i l.begin() i ! l.end() i)
  • cout ltlt i ltlt " "
  • list contains begin() and end() functions which
    return iterators pointing to the beginning and
    end of the list
  • template ltclass T, class A allocatorltTgt gt class
    list
  • public
  • typedef typename Asize_type size_type
  • typedef ... iterator
  • typedef ... const_iterator
  • iterator begin()
  • const_iterator begin() const
  • iterator end()
  • const_iterator end() const
  • ...

28
  • listltfloatgtiterator i
  • l.push_back(6.0)
  • l.push_back(7.0)
  • l.push_back(8.0)
  • l.push_back(9.0)
  • for(i l.begin() i ! l.end() i)
  • cout ltlt i ltlt " "
  • begin() returns an iterator which points to the
    first element of the list
  • end() returns an iterator which points one
    element past the last element in the list. This
    iterator does not point to a valid element (end()
    is sometimes used as a null iterator to
    indicate a non-existent element).

begin()
end()
6
7
8
9
29
  • As a second example of begin() and end(), the
    following prints a list in reverse order
  • listltfloatgtiterator i
  • l.push_back(6.0)
  • l.push_back(7.0)
  • l.push_back(8.0)
  • l.push_back(9.0)
  • for(i l.end() i ! l.begin() )
  • --i // move backwards in the list
  • cout ltlt i ltlt " "
  • This prints
  • 9 8 7 6

begin()
end()
6
7
8
9
30
Iterator categories
  • Not all iterators support the same operations.
    For instance, suppose we wrote a singly-linked
    list class
  • It would be impractical to iterate backwards
    through this list, since the links only point
    forward. So an iterator for singly linked lists
    might support , but not --.

begin()
end()
6
7
8
9
31
  • Iterators can be grouped into 5 categories, each
    supporting a different set of operations
  • output , for writing
  • input , , !, and -gt for reading
  • forward , , !, and -gt for reading and
    writing
  • bidirectional , --, , !, and -gt for
    reading and writing
  • random-access , --, , -, , -, , !, lt,
    gt, lt, gt, and -gt for reading and writing
  • Examples
  • a singly-linked list would create forward
    iterators
  • list (which is a doubly-linked list) creates
    bidirectional iterators
  • vector creates random-access iterators

32
  • These categories form a natural hierarchy
  • One might think that based on this hierarchy,
    iterators would be implemented as classes with
    appropriate virtual functions and overriding.
  • However, it was felt that virtual functions would
    be too inefficient for something as critical as
    iteration, so iterators were not implemented as
    classes with virtual functions.
  • In fact, iterators are not classes (or even
    types) at all! Instead, each category of
    iterator is just a set of conventions that
    various iterator implementations abide by.

input
forward
bidirectional
random-access
output
33
  • I said in the last lecture that it was bad style
    to use a template and to make many assumptions
    about the type T passed in
  • templateltclass Tgt // assumes T supports rotate,
    draw
  • void rotateAndDraw(T s, double angle)
  • s.rotate(angle)
  • s.draw()
  • Unfortunately, this is exactly what STL does with
    iterators. Sometimes this can be confusing, but
    as long as we understand what is required of the
    5 categories of iterators, we can live with it.

34
  • There are a couple more container operations,
    insert() and erase(), based on iterators
  • vector list
  • ----------------------------------------
  • vector() list()
  • vector(size, init_val)
  • push_back push_back
  • push_front
  • pop_back pop_back
  • pop_front
  • front front
  • back back
  • at
  • size size
  • empty empty
  • begin, end begin, end
  • insert insert
  • erase erase

35
  • insert adds a new element immediately before an
    iterator.
  • erase removes the element pointed to by an
    iterator
  • Example
  • listltfloatgt l
  • l.push_back(6.0)
  • l.push_back(7.0)
  • l.push_back(8.0)
  • l.push_back(9.0)
  • listltfloatgtiterator i l.begin()
  • i
  • l.insert(i, 17.0)
  • l.erase(i)
  • This results in the list 6.0, 17.0, 8.0, 9.0

36
  • Warning the erase operation causes all iterators
    that pointed to the erased element to be
    invalidated. So the following is illegal
  • listltfloatgtiterator i l.begin()
  • i
  • l.insert(i, 17.0)
  • l.erase(i)
  • l.insert(i, 18.0) // illegal! i is invalid here

37
  • For vectors, any operation that adds or removes
    elements invalidates all the iterators into the
    vector. This includes push_back, pop_back,
    insert, and erase
  • vectorltfloatgtiterator i v.begin()
  • i
  • v.push_back() // this invalidates the iterator i
  • v.insert(i, 17.0) // illegal! i is invalid here
  • The reason for this is that the vectors internal
    array may be copied to a new memory location when
    the array is resized, meaning that any iterators
    the pointed into the old array are no longer
    valid.
  • Also, remember that insertion and deletion are
    potentially expensive operations for vectors
    (though they are cheap operations for lists).
Write a Comment
User Comments (0)
About PowerShow.com