Object-Oriented Programming

CSCI-UA.0470-001

NYU, Undergraduate Division, Computer Science Course - Fall 2013

OOP Class Notes for 12/03/13

C++ Iterators

  • Every standard C++ container has a begin() and end() method. Begin returns an iterator pointing to the first element, and end returns a pointer after the last element.
  • In C++ iterators are smart pointers.
  • By dereferencing the iterator (*iter), we find what the iterator points to.
  • The code below uses iterator to traverse a string
    for(std::string::iterator iter = s.begin(); iter < s.end(); iter++) {  
    std::cout << iter std::endl;
    }
  • Every container in the standard template library has an interator
  • As we are told here, there are 5 kinds of iterators:
    1. Random Access
    2. Bidirectional
    3. Forward
    4. Input
    5. Output
  • To find what kind of iterator a container has, use the iterator_category method. For example:
  • std::string::iterator::iterator_category()
  • The above code creates a value representing the kind of iterator that string has.

Generalized Smart Pointers

  • In our smart pointer implementation we want to be flexible and have a reference counter that is not invasive. However, the call to our simulated virtual destructor is specific to our translator; the Ptr template is not general enough.
  • So we make templates for this, using three separate ways to destroy objects using generic parameters.
  • template<typename T>
    struct object_policy{
      static void destroy(T* addr) {
        delete addr; //deletes regular C++ class
      }
    };
        
    template<typename T>
    struct array_policy{
      static void destroy(T* addr) {
        delete[] addr; //deletes regular C++ array 
      }
    };
    
    template<typename T>
    struct java_policy{
      static void destroy(T* addr){
        if(0 != addr) addr -> __vptr->__delete(addr);
      }
    };
    
  • Such templates classes are called traits. The purpose of a trait is to carry information used by another object or algorithm to determine "policy" or "implementation details".
  • By using traits instead of inheritance we can avoid the run-time overhead of dynamic method dispatch for choosing the right implementation policy.
  • We integrate the destroy traits into our smart pointer class as follows:
  • template<typename T, template<typename> class P>
    class Ptr{
      .
      .
      .
    public:
      typedef T value_type;
      typedef P<T> policy_type;
      .
      .
      .
      policy_type::destroy(addr);
        
  • See for the complete code
  • Policies in action
  • __rt::Ptr<int, __rt::object_policy> p = new int(5);
    __rt::Ptr<double, __rt::array_policy> q = new double[5];
  • To avoid always writing out the second template argument, we can replace:
  • template<typename T, template <typename> class P>
  • with
  • template<typename T, template <typename> class P = object_policy>

What we learned

C++ Iterators
  • The different kind
  • Their corresponding tags
  • We can make versions of functions for different iterators and the correct one will automatically be selected.
Abstracting destroy line
  • Uses policy to pass a template that runs destroy based specifically on what needs to be destroyed.