// ==========================================================================
// $Id: std_autoptr.cpp,v 1.3 2011/09/10 01:08:19 jlang Exp $
// CSI2372 example Code for lecture 13
// ==========================================================================
// (C)opyright:
//
//   Jochen Lang
//   SITE, University of Ottawa
//   800 King Edward Ave.
//   Ottawa, On., K1N 6N5
//   Canada. 
//   http://www.site.uottawa.ca
// 
// Creator: jlang (Jochen Lang)
// Email:   jlang@site.uottawa.ca
// ==========================================================================
// $Log: std_autoptr.cpp,v $
// Revision 1.3  2011/09/10 01:08:19  jlang
// Updates F10
//
// Revision 1.2  2007/09/18 00:24:50  jlang
// Added comments
//
// Revision 1.1  2006/11/20 04:52:11  jlang
// Check-in for lecture 13
//
//
// ==========================================================================
#include <iostream>
#include <memory> 


using std::endl;
using std::cout;
using std::auto_ptr;
using std::ostream;

class A {
  int d_a;
public:
  A( int _a = 0) : d_a(_a) {
    cout << "A()" << endl;
  }
  virtual ~A() {
    cout << "~A()" << endl;
  }
  virtual void print() {
    cout << "A::print " << d_a << endl;
  }
  friend ostream& operator<<(ostream& os, const A& _obj ) {
    os << "A: " << _obj.d_a;
    return os;
  }
};

class B : public A {
public:
  B(int _a=0) : A(_a) {
    cout << "B()" << endl;
  }
  ~B() {
    cout << "~B()" << endl;
  }
  void print() {
    cout << "B::print" << endl;
  }
  friend ostream& operator<<(ostream& os, const B& _obj ) {
    os << "B";
    return os;
  }
};

template <class T>
void sink(auto_ptr<T> _ptr ) {
  cout << "Got an auto_ptr: " << *_ptr << endl;
  // destoyed at end of scope
}

template <class T>
auto_ptr<T> source( ) {
  auto_ptr<T> aPtr(new T());
  cout << "Made an auto_ptr: " << *aPtr << endl;
  // save to return -- will not leak memory 
  return aPtr;
}

int main( int argc, char* argv ) {
  auto_ptr<B> bPtr(new B(3));

  auto_ptr<A> aPtr = (auto_ptr<A>) bPtr;
  aPtr->print();
  cout << *aPtr << endl;
  if ( bPtr.get() == 0 ) {
    cout << "bPtr lost ownership" << endl;
  }
  // Assign to another A
  auto_ptr<A> aPtr2;
  aPtr2 = aPtr;
  // reset aPtr2 -- destroys B 
  // virtual destructor will take care of B part
  aPtr2.reset();

  //---------------------------------------- 
  cout << "Use functions with type B" <<  endl;
  bPtr = source<B>( ); 
  // get at raw ptr
  B* bRawPtr =  bPtr.get();
  bRawPtr->print();
  // destroy it
  sink( bPtr );

  cout << "Back from sink" << endl;
  return 0;
}
