Docstoc

Roadtrip Template

Document Sample
Roadtrip Template Powered By Docstoc
					   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
Goals
     STL Newbie
        – Convince you that it‟s a “good thing”
        – Help you avoid common mistakes
     STL Junkie
        – Add new STL techniques to your toolbox
        – Tricks and tips




 GDC Roadtrip Dec 1999
Preliminaries
  Microsoft Visual C++ 6.0
  Dinkumware STL implementation
  Benchmarks on Pentium III - 550MHz
  Performance graphs show relative
   performance – taller is better!




 GDC Roadtrip Dec 1999
History
  Alex Stepanov & Meng Lee, based on
   earlier work by Stepanov & Musser
  Proposed to C++ committee late „93
  HP version released „94
  Accepted into Standard summer „94
  Standard froze „97, ratified „98




 GDC Roadtrip Dec 1999
Advantages
  Standardized
  Thin & efficient
  Little inheritance; no virtual functions
  Small; easy to learn
  Flexible and extensible
  Naturally open source




 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
  Iterators : “container walkers” for
   accessing container elements
  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” pointer
        T Wallace[N];
        T* p = (Wallace + N); // valid pointer
        T w = *(Wallace + N); // invalid dereference

        c.begin() == (Wallace);   // first element
        c.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 example
        template <class InputItr, class T> InputItr
        find(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 algorithms
        using namespace std;   //   assume std::

        vector<int> Chuck;     // declare a growable array
        Chuck.push_back(1);    // add an element
        find(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


     Minimum container object requirements
        X()                                             //   default ctor
        X(const X&)                                     //   copy ctor
        X& operator = (const X&)                        //   assignment op
        bool operator < (const X&)                      //   comparison op
        bool operator == (const X&)                     //   comparison op

 GDC Roadtrip Dec 1999
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()
  Insert invals all iters if capacity change;
   insert/erase invals all iters following
 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
  Insert invals all iters; erase in middle
   invals all; erase at begin/end on invals
   iter to begin/end


 GDC Roadtrip Dec 1999
List
   Doubly-linked list
   Fast insert/erase; no random access
   Special functions: splice(), merge()
   Erase invals iters to erased elements;
    insert never invals any iters




  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)
  Erase invals erased elems; insert never
   invals any iters



 GDC Roadtrip Dec 1999
Map
  Dictionary of sorted elements
  List of sorted key and value pairs
  Same implementation and
   characteristics of set container




 GDC Roadtrip Dec 1999
Container Adaptors
 Adaptor                 Example containers   Default container
 stack          list, deque, vector           deque
 queue          list, deque                   deque
 priority_queue list, deque, vector           vector


    Example adapator code
       stack<int, deque<int> > TechnoTrousers;
       TechnoTrousers.push(1);
       int i = TechnoTrousers.top();
       TechnoTrousers.pop();




 GDC Roadtrip Dec 1999
What‟s Missing?
  stack-based arrays (T a[N])
  hash tables
  singly-linked lists
  some STL implementations include one
   or more of these “non-standard”
   containers



 GDC Roadtrip Dec 1999
Container Efficiency
  Container         Overhead   Insert             Erase              []      Find    Sort
  list              8          C                  C                  n/a     N       N log N
  deque             12         C at begin or      C at begin or      C       N       N log N
                               end; else N/2      end; else N
  vector            0          C at end; else N   C at end; else N   C       N       N log N
  set               12         log N              log N              n/a     log N   C
  multiset          12         log N              d log (N+d)        n/a     log N   C
  map               16         log N              log N              log N   log N   C
  multimap          16         log N              d log (N+d)        log N   log N   C
  stack             n/a        C                  C                  n/a     n/a     n/a
  queue             n/a        C                  C                  n/a     n/a     n/a
  priority_         n/a        log N              log N              n/a     n/a     n/a
  queue
  slist (SGI)       4          C                  C                  n/a     N       n/a
  hashset (SGI)     ?          C/N                C/N                n/a     C/N     n/a
  hashmap           ?          C/N                C/N                n/a     C/N     n/a
  (SGI)


     Overhead is approx. per-element size in bytes
     Hash and slist containers included for comparison only. C/N
      indicates best/worst case times

 GDC Roadtrip Dec 1999
Iterators
   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                Bidrect’l, i += n, i + n, i -= n, i – n,   vector<T>::iterator, deque<T>::iterator
                         i[n], i[n] = t



     Typical iteration
        c<T>::iterator i;
        for (i = c.begin(); i != c.end() ++i) // forward
           T t = *i;

        for (i = c.rbegin(); i != c.rend() ++i) // backward
           T t = *i;


 GDC Roadtrip Dec 1999
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 123
        int i = count(c.begin(), c.end(), 123);

        // negate all elements
        transform(c.begin(), c.end(), negate<int>());

        // print all elements
        for_each(c.begin(), c.end(), print<int>());

        // shuffle the deck
        random_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); }

        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); } };

        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 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‟);
        find(WestWallaby, WestWallaby+6, „m‟);


 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 allocator
        set<int, AllocSpecialCheese> Wensleydale;


 GDC Roadtrip Dec 1999
Template Partial Specialization
 // generic template function for swapping objects
 template <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 specialization
 template <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() algorithm
 template<class InItr, class OutItr> OutItr
 copy(InItr bg, InItr end, OutItr val)
 { for (; bg != end; ++val, ++bg)
      *val = *bg;
   return (val); }

 // A fast version for simple memory chunks
 template<> 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
Thread Safety
  Official answer: STL has no thread
   safety obligations whatsoever
  One (bad) answer: have STL handle all
   synchronization issues
  Typical answer: make STL thread safe
   internally, but require users to insure no
   thread accesses a container when
   another thread modifies the container

 GDC Roadtrip Dec 1999
Thread Safety (cont.)
     Current status of implementations
        – Original HP version not thread safe
        – SGI thread safe
        – VC mostly thread safe (dinkumware.com/vc_fixes.html)

     Typical STL implementation promises
        – Multiple reads is thread safe
        – Read/write across different containers, same objects, is
          thread safe
        – Writes to a container by one thread and read/writes by
          another thread is not thread safe; users must prevent

 GDC Roadtrip Dec 1999
Exception Safety
     C++ standard requires the following
        – destructors may not throw excptns
        – valid iterator operations may not throw
        – containers must “survive” excptns; content
          unspecified, but still destructable
        – an excptn thrown while inserting one
          element leaves the container unchanged
        – an excptn 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
  Some STL implementations are
   optimized to minimize code bloat (XTL
   from DeltaLogic)

 GDC Roadtrip Dec 1999
Compiler Warnings & Errors
     VC warning C4786: identifier truncation
        #pragma warning(disable: 4786) // before headers!


     Errors/warnings in header files
        – really means: your code has a problem

     Interpreting gonzo error messages
        map<string, int> m;
        map<string, int>const_iterator i = m.find(“abc”);
        m.erase(i); // “big” error here

 GDC Roadtrip Dec 1999
Compiler Errors (cont.)
 error   C2664    : 'class std::_Tree<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char>
         >,struct std::pair<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const
         ,int>,struct std::map<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,int,struct
         std::less<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,class
         std::allocator<int> >::_Kfn,struct std::less<class std::basic_string<char,struct std::char_traits<char>,class
         std::allocator<char> > >,class std::allocator<int> >::iterator __thiscall std::map<class std::basic_string<char,struct
         std::char_traits<char>,class std::allocator<char> >,int,struct std::less<class std::basic_string<char,struct
                                                                                           erase
         std::char_traits<char>,class std::allocator<char> > >,class std::allocator<int> >::         (class std::_Tree<class
         std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,struct std::pair<class
         std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const ,int>,struct std::map<class
         std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,int,struct std::less<class
         std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,class std::allocator<int>
         >::_Kfn,struct std::less<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,class
         std::allocator<int> >::iterator)' : cannot convert parameter 1 from                          'class std::_Tree<class
         std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,struct std::pair<class
         std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const ,int>,struct std::map<class
         std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,int,struct std::less<class
         std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,class std::allocator<int>
         >::_Kfn,struct std::less<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,class
         std::allocator<int> >::const_iterator' to               'class std::_Tree<class std::basic_string<char,struct
         std::char_traits<char>,class std::allocator<char> >,struct std::pair<class std::basic_string<char,struct
         std::char_traits<char>,class std::allocator<char> > const ,int>,struct std::map<class std::basic_string<char,struct
         std::char_traits<char>,class std::allocator<char> >,int,struct std::less<class std::basic_string<char,struct
         std::char_traits<char>,class std::allocator<char> > >,class std::allocator<int> >::_Kfn,struct std::less<class
         std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,class std::allocator<int>
         >::iterator'
           No constructor could take the source type, or constructor overload resolution was ambiguous




 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
Our own Algorithm
 // Compute sum of all squares in range
 template<class InItr, class T> T
 sumsqrs(InItr bg, InItr end, T init)
 { T ss(init);
    for (; bg != end; ++bg) { ss += (*bg) * (*bg); }
    return (ss); }

 int CloseShave[4] = { 1, 2, 3, 4 };
 int x = sumsqrs(CloseShave, CloseShave+4, 0); // 30

 deque<double> WrongTrousers; // 1.1, 2.2, 3.3
 double y = sumsqrs(WrongTrousers.begin(), // 16.94
                    WrongTrousers.end(), 0.0);


 GDC Roadtrip Dec 1999
Our own Iterator
 template <class C, class T, class A = allocator<T> >
 struct MfcIt : public _Ranit<T, A::difference_type> {
    C* mpC; // MFC container
    int mI; // index into container
    MfcIt(C* pC = 0)    : mpC(pC), mI(0) {}
    MfcIt(C* pC, int n) : mpC(pC), mI(n) {}
    MfcIt begin()      { return (MfcIt(mpC, 0)); }
    MfcIt end()        { return (MfcIt(mpC, mpC->GetSize())); }
    T&     operator * () const { return ((*mpC)[mI]); }
    MfcIt& operator ++ () { if (mI < mpC->GetSize()) ++mI; else mI = 0;
                            return (*this); }
    MfcIt operator + (difference_type n) const { MfcIt tmp = *this;
                                                   return (tmp += n); }
    bool   operator == (const MfcIt& i) const { return ((mI == i.mI) &&
                                                     (mpC == i.mpC)); }
    bool   operator < (const MfcIt& i) const { return ((mI < i.mI) &&
    (mpC == i.mpC)); }
 };

 GDC Roadtrip Dec 1999
Our own Iterator (cont.)
     Example of using the MFC/STL iterator
        // MFC container
        CStringArray arr;
        arr.Add("xyz");
        arr.Add("abc");

        // Create STL iterator from MFC container
        MfcIt<CStringArray, CString> mfc(&arr);

        // Sort the MFC container using an STL algorithm!
        sort(mfc.begin(), mfc.end());


 GDC Roadtrip Dec 1999
Common Mistakes
     Template of templates
        stack<vector<int>> GoneWrong; // need space: “> >”


     Same algorithm, different container
        sort(Marmalade.begin(), Jelly.end()) // crash!


     Right iterator, wrong container
        list<int>::iterator i = Feathers.begin();
        McGraw.erase(i); // i doesn‟t point into McGraw!


 GDC Roadtrip Dec 1999
Common Mistakes (cont.)
     Invalid iterator
        vector<int>::iterator i = GrandDayOut.begin();
        GrandDayOut.push_back(1); // potential realloc
        TheCooker(*i); // uh-oh! i might be invalid


     Adding elements with subscript op
        vector<char> Wendolene;
        Wendolene[0] = „W‟; // crash!
        Wendolene.push_back(„W‟); // the right way




 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 false
        – if      x<y && y<z are true, x<z is always false
        – 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 read
        map<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 file
        typedef          map<string, int> ShaunMap;
        typedef          pair<string, int> ShaunPair;
        typedef          ShaunMap::iterator ShaunItr;

        // Same code, but no more angle brackets
        ShaunMap Shaun;
        Shaun.insert(ShaunPair(“abc”, 31));
        ShaunItr i = Shaun.find(“abc”);
        ShaunPair pr = *i;



 GDC Roadtrip Dec 1999
Storing Pointers in Containers
  Container will not delete the pointers
   when the container goes away
  Will sort on pointer, not what it
   contains, unless you tell it otherwise
        deque<int*> Walkies;     // sorted by pointer
        sort(Walkies.begin(), Walkies.end());

        bool intpLess(const int* a, const int* j)
           { return (*a < *b); } // sorted by int
        sort(Walkies.begin(), Walkies.end(), intpLess);

 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 v
        copy(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 container
        v.erase(unique(v.begin(), v.end()), v.end());

        // Removes the given elements and shrinks v
        v.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
   expect arrays

 GDC Roadtrip Dec 1999
Deque vs Vector
  Almost identical usability characteristics
  Faster middle insertion because deque
   only needs to shift a chunk
  Constant-time insertion at the front
  Uses memory in a more operating
   system-friendly way
  Don‟t need to worry about reserve()


 GDC Roadtrip Dec 1999
The “Key” Requirement
  Once a key has been inserted into a
   container, the key should not change
  Can‟t be enforced internally by the STL
  Example: key is a filename; comparison
   is based on file contents




 GDC Roadtrip Dec 1999
Copy() vs Memcpy()
  copy() works reliably with all objects
  memcpy() unsafe on any object with a
   copy ctor
  copy() can copy a sequence whose
   length is not known in advance
  copy() returns an iter to the end of the
   copy; can be used as concatenation tool
  good implementation will optimize

 GDC Roadtrip Dec 1999
Wrap Up
       Algorithms, Containers, Iterators
       Efficient, Flexible, Extensible
       Angle Brackets... mmm




GDC Roadtrip Dec 1999
References
  Email me: PKIsensee@msn.com
  Home page: www.tantalon.com
  Books: Generic Programming & the STL
   (Austern), STL Tutorial & Reference
   Guid (Musser)
  Websites: sgi.com/Technology/STL,
   dinkumware.com, deltalogic.com,
   roguewave.com, stlport.org
 GDC Roadtrip Dec 1999

				
DOCUMENT INFO
Shared By:
Categories:
Tags:
Stats:
views:14
posted:7/22/2011
language:English
pages:59
Description: Roadtrip Template document sample