Listing 5

// a simple reference counted UN-smart pointer
#ifndef NDEBUG
  template<typename T>
  struct counted_ptr {
    counted_ptr(const new_ptr<T>& x) : mp(x.m), ref_count(new int(1)) {
    }
    counted_ptr() : mp(NULL), ref_count(NULL) {
    }
    bool operator==(const counted_ptr& x) const {
      return mp == x.mp;
    }
    bool operator!=(const counted_ptr& x) const {
      return mp != x.mp;
    }
    ~counted_ptr() {
      Release();
    }
    counted_ptr(const counted_ptr& x) {
      private_assign(x);
    }
    T* operator->() const {
      assert(mp != NULL);
      return mp;
    }
    T& operator*() const {
      assert(mp != NULL);
      return *mp;
    }
    operator const ptr<T, !deletable>&() {
      // only allows conversion to non-deletable pointers
      return mp;
    }
    void operator=(const counted_ptr& x) {
      if (*this == x) return; // change nothing
      Release();
      private_assign(x);
    }
    void Release() {
      if (mp == NULL) return;
      assert(ref_count != NULL && "implementation error");
      --(*ref_count);
      assert(*ref_count > 0 && "orphaning memory");
      mp = NULL;
    }
    void Delete() {
      if (mp == NULL) {
        assert(ref_count == NULL && "implementation error");
        return;
      }
      assert(ref_count != NULL && "implementation error");
      assert(*ref_count == 1 && "can not delete when other 
                                         references still remain");
      delete ref_count;
      delete mp;
      mp = NULL;
    }
    static counted_ptr Null() {
      return counted_ptr();
    }
  private:
    void private_assign(const counted_ptr& x) {
      // private, because it is unsafe. The public methods 
      //                         make sure everything is kosher
      mp = x.mp;
      ref_count = x.ref_count;
      if (mp != NULL) {
        assert(ref_count != NULL && "implementation error");
        ++(*ref_count);
      } else {
        assert(ref_count == NULL && "implementation error");
      }
    }
  private:
    T* mp;
    int* ref_count;
  };
#else
  template<typename T>
  struct counted_ptr {
    counted_ptr(const new_ptr<T>& x) : mp(x.m) {
    }
    counted_ptr() : mp(NULL){
    }
    bool operator==(const counted_ptr& x) const {
      return mp == x.mp;
    }
    bool operator!=(const counted_ptr& x) const {
      return mp != x.mp;
    }
    counted_ptr(const counted_ptr& x) {
      mp = x.mp;
    }
    T* operator->() const {
      return mp;
    }
    T& operator*() const {
      return *mp;
    }
    operator const ptr<T, !deletable>&() {
      return mp;
    }
    void operator=(const counted_ptr& x) {
      mp = x.mp;
    }
    void release() {
      mp = NULL;
    }
    void Delete() {
      delete mp;
      mp = NULL;
    }
    static counted_ptr null() {
      return counted_ptr();
    }
  };
#endif