Upload
lorena-bell
View
222
Download
2
Embed Size (px)
Citation preview
Embracing the C++ STL:Why Angle Brackets are
Good for You
Pete Isensee
•GDC Roadtrip Dec 1999
Introduction
• STL Background & History• Key Concepts• Containers, Iterators and Algorithms• Efficiency and Thread Safety• Tips and Tricks
•GDC Roadtrip Dec 1999
Disadvantages
• Template syntax• Difficult to read & decipher• Poor or incomplete compiler support• Code bloat potential• No constraints on template types• Limited container types
•GDC Roadtrip Dec 1999
Key Concepts
• Generic algorithms• Container classes (data structures)• Iterators : “container walkers” for accessing
container elements (smart pointers)• Iterators provide an abstraction of container
access, which in turn allows for generic algorithms
• Iterator invalidation
•GDC Roadtrip Dec 1999
Key Concepts (cont.)
• Ranges: C/C++ “past-the-end” pointerT Wallace[N];T* p = (Wallace + N); // valid pointerT w = *(Wallace + N); // invalid dereference
c.begin() == (Wallace); // first elementc.end() == (Wallace + N); // valid iterator*c.end(); // invalid dereference
• end() - begin() = size()• if (begin() == end()) container is empty
• for (iter i = begin(); i != end(); ++i)•GDC Roadtrip Dec 1999
Key Concepts (cont.)
• Linear search exampletemplate <class InputItr, class T> InputItrfind(InputItr bg, InputItr end, const T& val){ while (bg != end && *bg != val) ++bg; return (bg); }
const int nSize = 4;int Gromit[nSize] = { 5, 18, 23, 9 };int* pFind = find(Gromit, Gromit + nSize, 23);
vector<int> Preston;vector<int>::iterator i = find(Preston.begin(), Preston.end(), 4);
•GDC Roadtrip Dec 1999
Putting the STL into Action
• Include files have no “.h”• Standard namespace
#include <cstdio> // new include method#include <vector> // vector container#include <algorithm> // STL algorithmsusing namespace std; // assume std::
vector<int> Chuck; // declare a growable arrayChuck.push_back(1); // add an elementfind(Chuck.begin(), Chuck.end(), 1);
•GDC Roadtrip Dec 1999
Containers
• Containers contain elements; they “own” the objects
• Containers provide iterators that point to its elements.
• Containers provide a minimal set of operations for manipulating elements
•GDC Roadtrip Dec 1999
Containers (cont.)
Container Description Keys
vector dynamic array deque dynamic array -- both ends list linked list set sorted list of keys no duplicate keys map sorted list of key and value pairs no duplicate keys multiset sorted list of keys duplicate keys OK multimap sorted list of key and value pairs duplicate keys OK
•GDC Roadtrip Dec 1999
Minimum container object requirements
X() // default constructorX(const X&) // copy constructorX& operator = (const X&) // assignment opbool operator < (const X&) // comparison opbool operator == (const X&) // comparison op
Vector
• Dynamic array• Fast ins/erase from end of vector• reserve(), capacity()• Contiguous block of memory• Obliged to grow by some factor (2x) when
size() exceeds capacity()
•GDC Roadtrip Dec 1999
Deque
• Double-ended queue (“deck”)• Fast ins/erase at begin and end• Directory array of pointers to nodes, where
each node is small array of T
•GDC Roadtrip Dec 1999
List
• Doubly-linked list• Fast insert/erase; no random access• Special functions: splice(), merge()
•GDC Roadtrip Dec 1999
Set
• List of sorted elements • Fast retrieval based on key (log N)• Fast insert/erase (log N)• Red-black tree (balanced 2-3-4 tree)
•GDC Roadtrip Dec 1999
Map
• Associative array• Dictionary of sorted elements• List of sorted key and value pairs• Same implementation and characteristics of
set container
•GDC Roadtrip Dec 1999
Container Adaptors
• Example adapator code
stack<int, deque<int> > TechnoTrousers;TechnoTrousers.push(1);int i = TechnoTrousers.top();TechnoTrousers.pop();
•GDC Roadtrip Dec 1999
Adaptor Example containers Default container stack list, deque, vector deque queue list, deque deque priority_queue list, deque, vector vector
Iterators
• Typical iterationc<T>::iterator i;
for (i = c.begin(); i != c.end(); ++i) // forward T t = *i;
for (i = c.rbegin(); i != c.rend(); ++i) // reverse T t = *i;
•GDC Roadtrip Dec 1999
Type Valid expressions Example Input *t, ++i, i++, *i++ find() (read-only) Output *x = t, *x++ = t, ++x, x++ insert_iterator<C> (write-only) Forward ++i, i++, *x=t slist<T>::iterator (SGI-specific) Bidirectional ++i, i++, --i, i--, *x=t list<T>::iterator
Random Access
Bidrectional i+=n, i+n, i-=n, i–n, i[n], i[n]=t
vector<T>::iterator, deque<T>::iterator
Algorithms
• Approx. 60 standard algorithms– searching e.g. find()– sorting e.g. sort()– mutating e.g. transform()– numerical e.g. accumulate()
• Most functions take the form:– fn(c.begin(), c.end(), ...)
•GDC Roadtrip Dec 1999
Algorithms (cont.)
• Examples:#include <algorithm>
// return num elements equal to 123int i = count(c.begin(), c.end(), 123);
// negate all elementstransform(c.begin(), c.end(), negate<int>());
// print all elementsfor_each(c.begin(), c.end(), print<int>());
// shuffle the deckrandom_shuffle(deck.begin(), deck.end());
•GDC Roadtrip Dec 1999
Function Objects (Functors)
• C++ objects that can be called like a function to implement “callbacks”
• Use C++ operator()(...)• Simplest type is a function pointer
bool StlStrComp(const char* a, const char* b) { return (strcmp(a, b) == -1); } ( < 0 )??
vector<char*> v;sort(v.begin(), v.end(), StlStrComp);
•GDC Roadtrip Dec 1999
Functors (cont.)
• Functors that do ordering are called “predicates”
struct StlStrPred // “public” class{ bool operator()(const char* a, const char* b) { return (strcmp(a, b) == -1); } ( < 0 )};
vector<char*> v;sort(v.begin(), v.end(), StlStrPred());
•GDC Roadtrip Dec 1999
Efficiency
• Designed to be as fast as hand-coded routines• Limiting factor is typically copy ctor
(constructor) and assignment operator
•GDC Roadtrip Dec 1999
Efficiency (cont.)
• STL faster in some cases than standard C functions
const char* WestWallaby = “Gromit”;strchr(WestWallaby, ‘m’); //cfind(WestWallaby, WestWallaby+6, ‘m’); //c++
•GDC Roadtrip Dec 1999
Efficiency (cont.)
• Sorting (ints)
int arr[nElements];qsort(arr, nElements, sizeof(int), IntComp);
int arr[nElements];sort(arr, arr + nElements); // STL int array sort
vector<int> v;sort(v.begin(), v.end()); // STL int vector sort
•GDC Roadtrip Dec 1999
Efficiency (cont.)
• Sorting (strings)
char* arr[nElements];qsort(arr, nElements, sizeof(char*), StrComp);
sort(arr, arr + nElements, StlStrComp);
sort(v.begin(), v.end(), StlStrComp); // char*
sort(v.begin(), v.end(), StlStrComp); // string
•GDC Roadtrip Dec 1999
STL Allocators
• Every STL container takes an allocator object as a template parameter
template <class T> public AllocSpecialCheese{ public: pointer allocate(size_type, const void*); void deallocate(void*, size_type); // ... other boilerplate code here};
set<int> Camembert; // default allocator
// All Wensleydale allocations use special allocatorset<int, AllocSpecialCheese> Wensleydale;
•GDC Roadtrip Dec 1999
Template Partial Specialization// generic template function for swapping objectstemplate <class T> void swap(T& x, T& y) { T z(x); x = y; y = z; }
swap(v1, v2); // swapping vectors: slow!v1.swap(v2); // swapping vectors: fast!
// template partial specializationtemplate <class T> void swap(vector<T>& x, vector<T>& y) { x.swap(y); }
swap(v1, v2); // fast!
•GDC Roadtrip Dec 1999
Template Specialization part II // STL generic copy() algorithmtemplate<class InItr, class OutItr> OutItrcopy(InItr bg, InItr end, OutItr val){ for (; bg != end; ++val, ++bg) *val = *bg; return (val); }
// A fast version for simple memory chunkstemplate<> char* copy(const char* bg, const char* end, char* val){ size_t n = end - bg; memcpy(val, bg, n); return (val + n); }
•GDC Roadtrip Dec 1999
Exception Safety
• C++ standard requires the following– destructors may not throw exceptions– valid iterator operations may not throw exceptions– containers must “survive” exceptions; content
unspecified, but still destructable– an exception thrown while inserting one element
leaves the container unchanged– an exception thrown while inserting two+
elements leaves a list unchanged
•GDC Roadtrip Dec 1999
Code Bloat
• Templates expand into different sets of code for each type T
• If different types have the same size and same comparison functions, the compiler can optimize
•GDC Roadtrip Dec 1999
Extending the STL
• Designed for extension• Not difficult to write new algorithms,
containers, or iterators• SGI implementation has many useful
container extensions (hash tables, slist)
•GDC Roadtrip Dec 1999
Common Mistakes (cont.)
• Sorting problems– e.g. lookups fail, a set gets duplicates
• Usually a problem with op < or op ==• Rules
– if x<y is true, y>x is always true– if x<y && y<z are true, x<z is always true– if x==y, then x<y is always false– if !(x<y) and !(y<x), x == y
•GDC Roadtrip Dec 1999
Hiding the Angle Brackets
• Not pretty
// This is hard to readmap<string, int> Shaun;Shaun.insert(pair<string, int>(“abc”, 31));map<string, int>::iterator i = Shaun.find(“abc”);pair<string, int> pr = *i;
pr.first; // “abc”pr.second; // int
•GDC Roadtrip Dec 1999
Hiding the Angle Brackets (cont.)
• Typedefs are your friend
// Tuck these away in a header filetypedef map<string, int> ShaunMap;typedef pair<string, int> ShaunPair;typedef ShaunMap::iterator ShaunItr;
// Same code, but no more angle bracketsShaunMap Shaun;Shaun.insert(ShaunPair(“abc”, 31));ShaunItr i = Shaun.find(“abc”);ShaunPair pr = *i;
•GDC Roadtrip Dec 1999
Vector Tips
• Use reserve() to set aside space when vector size is known in advance
• Can I safely take the address of a vector element, e.g. &v[21]?– According to Standard, no. According to practice,
yes. Standard expected to adjust.
• Trimming unused space
v.swap(vector<T>(v)); // vector, swap thyself!
•GDC Roadtrip Dec 1999
Copying Containers
• The wrong way; copy() can’t add elems
copy(v.begin(), v.end(), nv.begin()); // uh-oh
• Better and best
nv.resize(v.size()); // size of nv matches vcopy(v.begin(), v.end(), nv.begin());
copy(v.begin(), v.end(), back_inserter(nv));copy(m.begin(), m.end(), insert_iterator<T> /* map and set use this method */ (nm, nm.begin());
•GDC Roadtrip Dec 1999
Algorithms that Remove Elems
• Algorithms by themselves can’t insert or delete elements, so they move them!
• unique() moves unique elems to the front and returns an iter to the new “end” of the container
• remove() similarly moves the “unremoved” elems to the front and returns an iter to the new “end”
•GDC Roadtrip Dec 1999
Removing Elems (cont.)
• To actually get rid of the extra elems, you must call erase()
// Removes duplicates and shrinks the containerv.erase(unique(v.begin(), v.end()), v.end());
// Removes the given elements and shrinks vv.erase(remove(v.begin(), v.end(), 1), v.end());
•GDC Roadtrip Dec 1999
Vectors vs C-style arrays
• Prefer vector or deque over arrays• Don’t have to know size in advance• Don’t have to keep track of size separately• Little loss of efficiency• Vector works well with legacy code that
expects arrays
•GDC Roadtrip Dec 1999