Thread: Smart Pointers

  1. #1
    Registered User
    Join Date
    Dec 2014
    Posts
    143

    Smart Pointers

    I was reading into std::shared_ptr and I got to thinking...how does it keep up with a reference count?

  2. #2
    [](){}(); manasij7479's Avatar
    Join Date
    Feb 2011
    Location
    *nullptr
    Posts
    2,657
    With a counter!
    You set the counter to 1 when you first allocate the memory.
    After that copy construction/assignment copies the counter along with the data and increments it.
    The destructor is interesting.
    You decrement your counter and if it reaches zero, you deallocate the data.

  3. #3
    Registered User
    Join Date
    Dec 2014
    Posts
    143
    Yes with a counter but if each smart pointer has its own counter, then they will all have different values and it wouldn't help you at all.

  4. #4
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    All shared pointers that point to the same resource share the counter.
    When you first create a shared_ptr, you create a counter on the heap.
    When you copy a shared_ptr, you copy that pointer to the counter to the new smart pointers and increase the ref count.
    When a smart_ptr is destroyed, you decrease the ref counter.
    When all pointers to the resource are destroyed, the free the counter and the resource.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  5. #5
    Registered User Alpo's Avatar
    Join Date
    Apr 2014
    Posts
    877
    Quote Originally Posted by manasij7479 View Post
    With a counter!
    You set the counter to 1 when you first allocate the memory.
    After that copy construction/assignment copies the counter along with the data and increments it.
    The destructor is interesting.
    You decrement your counter and if it reaches zero, you deallocate the data.
    This makes sense. It gets harder to account for when you consider you need a way to increment or decrement the reference count only for pointers sharing the same value. You could probably do this with a static map (having just a single variable to do the counting seems impossible).
    WndProc = (2[b] || !(2[b])) ? SufferNobly : TakeArms;

  6. #6
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    It's not difficult at all. Create a smart pointer and a reference count on the heap. All copies of that smart pointer copies the pointer to the ref counter. Now all instances that points to that share the ref counter.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  7. #7
    Registered User Alpo's Avatar
    Join Date
    Apr 2014
    Posts
    877
    Quote Originally Posted by Elysia View Post
    It's not difficult at all. Create a smart pointer and a reference count on the heap. All copies of that smart pointer copies the pointer to the ref counter. Now all instances that points to that share the ref counter.
    Still you would still need some structure to memorize that a certain pointer value is associated with a certain reference counter (pointer) value, right?

    Like for instance if I have two shared pointers of the same template type, that are pointing to two different objects of the same type. This would mean I need two reference counters, right? When I go to copy one of the shared pointers to object A, how do I know which reference counter to give to the copy?

    (Sorry if I'm being frustrating lol, I really am trying to understand ).

    Edit: I'm an idiot lol, I see what you are saying, the object being copied has it's own reference counter. Forgive me I got stuck on this "static variable" idea for some reason.
    Last edited by Alpo; 05-09-2015 at 09:18 PM.
    WndProc = (2[b] || !(2[b])) ? SufferNobly : TakeArms;

  8. #8
    Registered User
    Join Date
    Dec 2014
    Posts
    143
    So is this kinda what you are saying?

    Code:
    #ifndef __POINTER_H
    #define __POINTER_H
    
    
    #include <iostream>
    
    
    template <class T>
    class Pointer {
    
    
    public:
    	/* Constructors/Destructor */
    	Pointer();
    	Pointer(T *ptr);
    	Pointer(const Pointer<T>& ptr);
    	~Pointer();
    
    
    	/* Modifiers */
    	void reset();
    
    
    	/* Accessors */
    	T* raw();
    	int count();
    	T& operator [] (const size_t& index);
    	T& operator * ();
    	T& operator -> ();
    	T** operator & ();
    
    
    	/* Assignment Operators */
    	Pointer<T>& operator = (T *ptr);
    	Pointer<T>& operator = (const Pointer<T>& ptr);
    
    
    	/* Arithmetic Assignment Operators */
    	Pointer<T>& operator ++ ();
    	Pointer<T> operator ++ (int);
    	Pointer<T>& operator -- ();
    	Pointer<T> operator -- (int);
    	template <class U> Pointer<T>& operator += (const U& other);
    	template <class U> Pointer<T>& operator -= (const U& other);
    	template <class U> Pointer<T>& operator *= (const U& other);
    	template <class U> Pointer<T>& operator /= (const U& other);
    	template <class U> Pointer<T>& operator %= (const U& other);
    	template <class U> Pointer<T>& operator >>= (const U& other);
    	template <class U> Pointer<T>& operator <<= (const U& other);
    	template <class U> Pointer<T>& operator &= (const U& other);
    	template <class U> Pointer<T>& operator |= (const U& other);
    	template <class U> Pointer<T>& operator ^= (const U& other);
    
    
    	/* Relational Operators */
    	template <class U> friend bool operator == (const Pointer<T>& ptr, const U& other);
    	template <class U> friend bool operator != (const Pointer<T>& ptr, const U& other);
    	template <class U> friend bool operator >= (const Pointer<T>& ptr, const U& other);
    	template <class U> friend bool operator <= (const Pointer<T>& ptr, const U& other);
    	template <class U> friend bool operator > (const Pointer<T>& ptr, const U& other);
    	template <class U> friend bool operator < (const Pointer<T>& ptr, const U& other);
    
    
    	/* Conversions */
    	bool operator ! ();
    	template <class U> operator U();
    	template <class U> operator U*();
    	template <class U> operator Pointer<U>();
    
    
    	/* Std Overloads */
    	friend std::ostream& operator << (std::ostream& os, const Pointer<T>& ptr);
    
    
    protected:
    	T *rawPointer;
    	int *refCounter;
    };
    
    
    template <class T>
    Pointer<T>::Pointer() {
    	
    	refCounter = new int;
    	*refCounter = 0;
    	rawPointer = nullptr;
    }
    
    
    template <class T>
    Pointer<T>::Pointer(T *ptr) {
    
    
    	refCounter = new int;
    	*refCounter = 1;
    	rawPointer = ptr;
    }
    
    
    template <class T>
    Pointer<T>::Pointer(const Pointer<T>& ptr) {
    
    
    	if (*ptr.refCounter)
    		refCounter = ++*ptr.refCounter;
    	else
    		refCounter = nullptr;
    
    
    	rawPointer = ptr.rawPointer;
    }
    
    
    template <class T>
    Pointer<T>::~Pointer() {
    
    
    	if (--*refCounter == 0)
    		delete[] rawPointer;
    }
    
    
    template <class T>
    void Pointer<T>::reset() {
    
    
    	if (--*refCounter == 0)
    		delete[] rawPointer;
    
    
    	rawPointer = nullptr;
    }
    
    
    template <class T>
    T* Pointer<T>::raw() {
    
    
    	return rawPointer;
    }
    
    
    template <class T>
    int count() {
    	
    	return *refCounter;
    }
    
    
    template <class T>
    T& Pointer<T>::operator [] (const size_t& index) {
    
    
    	return rawPointer[index];
    }
    
    
    template <class T>
    T& Pointer<T>::operator * () {
    
    
    	return *rawPointer;
    }
    
    
    template <class T>
    T& Pointer<T>::operator -> () {
    
    
    	return *rawPointer
    }
    
    
    template <class T>
    T** Pointer<T>::operator & () {
    
    
    	return &rawPointer;
    }
    
    
    template <class T>
    Pointer<T>& Pointer<T>::operator = (T *ptr) {
    
    
    	if (rawPointer != ptr) {
    		if (--*refCounter == 0)
    			delete[] rawPointer;
    		
    		refCounter = new int;
    		*refCounter = 1;
    		rawPointer = ptr;
    	}
    }
    
    
    template <class T>
    Pointer<T>& Pointer<T>::operator = (const Pointer<T>& ptr) {
    
    
    	if (rawPointer != ptr.rawPointer) {
    		if (--*refCounter == 0)
    			delete[] rawPointer;
    
    
    		refCounter = ++*ptr.refCounter;
    		rawPointer = ptr.rawPointer;
    	}
    }
    
    
    template <class T>
    Pointer<T>& Pointer<T>::operator ++ () {
    
    
    	if (--*refCounter == 0)
    		delete[] rawPointer;
    
    
    	refCounter = new int;
    	*refCounter = 1;
    	++rawPointer;
    }
    
    
    template <class T>
    Pointer<T> Pointer<T>::operator ++ (int) {
    
    
    	if (--*refCounter == 0)
    		delete[] rawPointer;
    
    
    	refCounter = new int;
    	*refCounter = 1;
    	++rawPointer;
    }
    
    
    template <class T>
    Pointer<T>& Pointer<T>::operator -- () {
    
    
    	if (--*refCounter == 0)
    		delete[] rawPointer;
    
    
    	refCounter = new int;
    	*refCounter = 1;
    	--rawPointer;
    }
    
    
    template <class T>
    Pointer<T> Pointer<T>::operator -- (int) {
    
    
    	if (--*refCounter == 0)
    		delete[] rawPointer;
    
    
    	refCounter = new int;
    	*refCounter = 1;
    	--rawPointer;
    }
    
    
    template <class T> template <class U> 
    Pointer<T>& Pointer<T>::operator += (const U& other) {
    
    
    	if (--*refCounter == 0)
    		delete[] rawPointer;
    
    
    	refCounter = new int;
    	*refCounter = 1;
    	rawPointer += other;
    }
    
    
    template <class T> template <class U> 
    Pointer<T>& Pointer<T>::operator -= (const U& other) {
    
    
    	if (--*refCounter == 0)
    		delete[] rawPointer;
    
    
    	refCounter = new int;
    	*refCounter = 1;
    	rawPointer -= other;
    }
    
    
    template <class T> template <class U> 
    Pointer<T>& Pointer<T>::operator *= (const U& other) {
    
    
    	if (--*refCounter == 0)
    		delete[] rawPointer;
    
    
    	refCounter = new int;
    	*refCounter = 1;
    	rawPointer *= other;
    }
    
    
    template <class T> template <class U> 
    Pointer<T>& Pointer<T>::operator /= (const U& other) {
    
    
    	if (--*refCounter == 0)
    		delete[] rawPointer;
    
    
    	refCounter = new int;
    	*refCounter = 1;
    	rawPointer /= other;
    }
    
    
    template <class T> template <class U> 
    Pointer<T>& Pointer<T>::operator %= (const U& other) {
    
    
    	if (--*refCounter == 0)
    		delete[] rawPointer;
    
    
    	refCounter = new int;
    	*refCounter = 1;
    	rawPointer %= other;
    }
    
    
    template <class T> template <class U> 
    Pointer<T>& Pointer<T>::operator >>= (const U& other) {
    
    
    	if (--*refCounter == 0)
    		delete[] rawPointer;
    
    
    	refCounter = new int;
    	*refCounter = 1;
    	rawPointer >>= other;
    }
    
    
    template <class T> template <class U> 
    Pointer<T>& Pointer<T>::operator <<= (const U& other) {
    
    
    	if (--*refCounter == 0)
    		delete[] rawPointer;
    
    
    	refCounter = new int;
    	*refCounter = 1;
    	rawPointer <<= other;
    }
    
    
    template <class T> template <class U> 
    Pointer<T>& Pointer<T>::operator &= (const U& other) {
    
    
    	if (--*refCounter == 0)
    		delete[] rawPointer;
    
    
    	refCounter = new int;
    	*refCounter = 1;
    	rawPointer &= other;
    }
    
    
    template <class T> template <class U> 
    Pointer<T>& Pointer<T>::operator |= (const U& other) {
    
    
    	if (--*refCounter == 0)
    		delete[] rawPointer;
    
    
    	refCounter = new int;
    	*refCounter = 1;
    	rawPointer |= other;
    }
    
    
    template <class T> template <class U> 
    Pointer<T>& Pointer<T>::operator ^= (const U& other) {
    
    
    	if (--*refCounter == 0)
    		delete[] rawPointer;
    
    
    	refCounter = new int;
    	*refCounter = 1;
    	rawPointer ^= other;
    }
    
    
    template <class T> template <class U> 
    bool Pointer<T>::operator == (const Pointer<T>& ptr, const U& other) {
    
    
    	return (rawPointer == other);
    }
    
    
    template <class T> template <class U> 
    bool Pointer<T>::operator != (const Pointer<T>& ptr, const U& other) {
    
    
    	return (rawPointer != other);
    }
    
    
    template <class T> template <class U> 
    bool Pointer<T>::operator >= (const Pointer<T>& ptr, const U& other) {
    
    
    	return (rawPointer >= other);
    }
    
    
    template <class T> template <class U> 
    bool Pointer<T>::operator <= (const Pointer<T>& ptr, const U& other) {
    
    
    	return (rawPointer <= other);
    }
    
    
    template <class T> template <class U> 
    bool Pointer<T>::operator > (const Pointer<T>& ptr, const U& other) {
    
    
    	return (rawPointer > other);
    }
    
    
    template <class T> template <class U> 
    bool Pointer<T>::operator < (const Pointer<T>& ptr, const U& other) {
    
    
    	return (rawPointer < other);
    }
    
    
    template <class T>
    bool Pointer<T>::operator ! () {
    
    
    	return !rawPointer;
    }
    
    
    template <class T> template <class U> 
    Pointer<T>::operator U() {
    
    
    	return rawPointer;
    }
    
    
    template <class T> template <class U> 
    Pointer<T>::operator U*() {
    
    
    	return rawPointer;
    }
    
    
    template <class T> template <class U> 
    Pointer<T>::operator Pointer<U>() {
    
    
    	Pointer<U> ptr;
    	ptr.refCounter = refCounter;
    	ptr.rawPointer = rawPointer;
    }
    
    
    template <class T>
    std::ostream& operator << (std::ostream& os, const Pointer<T>& ptr) {
    
    
    	return (os << rawPointer);
    }
    
    
    #endif // __POINTER_H

  9. #9
    Registered User
    Join Date
    Dec 2013
    Posts
    241
    these 2 functions will cause memory leak:

    Code:
    template <class T>
    Pointer<T>::Pointer() {
         
        refCounter = new int;
        *refCounter = 0;
        rawPointer = nullptr;
    }
    
    template <class T>
    Pointer<T>::~Pointer() {
     
     
    
        if (--*refCounter == 0)
    
            delete[] rawPointer;
    
    }
    you never delete counter (actually in any function..).

    (I also don't get the whole mathematical operators += , -= etc. if they reflect pointer arithmatics - your implementation is not.. )
    Last edited by Dave11; 05-09-2015 at 11:52 PM.

  10. #10
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by cmajor28 View Post
    So is this kinda what you are saying?
    Kind of, yes, though there are some bugs in there.
    Then there's all the operators involved which makes it a little more complicated. Like, do you want to allow assigning raw pointers? You could theoretically pull one from another smart pointer and add assign it to a different one. That way, you could two difference reference counts, which I believe, is why the standard prohibits this kind of thing.

    Also, operator < is usually overloaded to do the comparison *p < value to make smart pointers play nice with containers.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  11. #11
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    So is this kinda what you are saying?
    O_o

    You have just so many copy/paste bugs.

    Also, operator < is usually overloaded to do the comparison *p < value to make smart pointers play nice with containers.
    Stop talking nonsense.

    Virtually all smart pointers overload the comparison operators as to forward comparison to the underlying values of the owned pointers not the values at which the pointers point.

    Soma
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  12. #12
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by phantomotap View Post
    Stop talking nonsense.

    Virtually all smart pointers overload the comparison operators as to forward comparison to the underlying values of the owned pointers not the values at which the pointers point.

    Soma
    Guess I remember wrong then.
    *shrug*
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  13. #13
    Registered User
    Join Date
    Dec 2014
    Posts
    143
    I put it together really quick. I overloaded all of the assignment stuff because actual pointers let you do that. As for + - and such, the conversion operator takes care of those. I'm looking at my code and I'm baffled, when do I need to delete the reference counter?

    EDIT: I think I found where...

    BTW delete[] refCounter should be delete refCounter

    Code:
    #ifndef __POINTER_H
    #define __POINTER_H
    
    
    #include <iostream>
    
    
    template <class T>
    class Pointer {
    
    
    public:
        /* Constructors/Destructor */
        Pointer();
        Pointer(T *ptr);
        Pointer(const Pointer<T>& ptr);
        ~Pointer();
    
    
        /* Modifiers */
        void reset();
    
    
        /* Accessors */
        T* raw();
        int count();
        T& operator [] (const size_t& index);
        T& operator * ();
        T& operator -> ();
        T** operator & ();
        const T* raw() const;
        const int count() const;
        const T& operator [] (const size_t& index) const;
        const T& operator * () const;
        const T& operator -> () const;
        const T** operator & () const;
    
    
        /* Assignment Operators */
        Pointer<T>& operator = (T *ptr);
        Pointer<T>& operator = (const Pointer<T>& ptr);
    
    
        /* Arithmetic Assignment Operators */
        Pointer<T>& operator ++ ();
        Pointer<T> operator ++ (int);
        Pointer<T>& operator -- ();
        Pointer<T> operator -- (int);
        template <class U> Pointer<T>& operator += (const U& other);
        template <class U> Pointer<T>& operator -= (const U& other);
        template <class U> Pointer<T>& operator *= (const U& other);
        template <class U> Pointer<T>& operator /= (const U& other);
        template <class U> Pointer<T>& operator %= (const U& other);
        template <class U> Pointer<T>& operator >>= (const U& other);
        template <class U> Pointer<T>& operator <<= (const U& other);
        template <class U> Pointer<T>& operator &= (const U& other);
        template <class U> Pointer<T>& operator |= (const U& other);
        template <class U> Pointer<T>& operator ^= (const U& other);
    
    
        /* Relational Operators */
        template <class U> friend bool operator == (const Pointer<T>& ptr, const U& other);
        template <class U> friend bool operator != (const Pointer<T>& ptr, const U& other);
        template <class U> friend bool operator >= (const Pointer<T>& ptr, const U& other);
        template <class U> friend bool operator <= (const Pointer<T>& ptr, const U& other);
        template <class U> friend bool operator > (const Pointer<T>& ptr, const U& other);
        template <class U> friend bool operator < (const Pointer<T>& ptr, const U& other);
    
    
        /* Conversions */
        bool operator ! ();
        template <class U> operator U();
        template <class U> operator U*();
        template <class U> operator Pointer<U>();
    
    
        /* Std Overloads */
        friend std::ostream& operator << (std::ostream& os, const Pointer<T>& ptr);
    
    
    protected:
        T *rawPointer;
        int *refCounter;
    };
    
    
    template <class T> inline
    Pointer<T>::Pointer() {
        
        refCounter = new int;
        *refCounter = 0;
        rawPointer = nullptr;
    }
    
    
    template <class T> inline
    Pointer<T>::Pointer(T *ptr) {
    
    
        refCounter = new int;
        *refCounter = 1;
        rawPointer = ptr;
    }
    
    
    template <class T> inline
    Pointer<T>::Pointer(const Pointer<T>& ptr) {
    
    
        if (*ptr.refCounter)
            refCounter = ++*ptr.refCounter;
        else
            refCounter = nullptr;
    
    
        rawPointer = ptr.rawPointer;
    }
    
    
    template <class T> inline
    Pointer<T>::~Pointer() {
    
    
        if (*refCounter == 0)
            delete[] refCounter;
        else if (--*refCounter == 0)
            delete[] rawPointer;
    }
    
    
    template <class T> inline
    void Pointer<T>::reset() {
    
    
        if (*refCounter == 0)
            delete[] refCounter;
        else if (--*refCounter == 0)
            delete[] rawPointer;
    
    
        refCounter = new int;
        *refCounter = 0;
        rawPointer = nullptr;
    }
    
    
    template <class T> inline
    T* Pointer<T>::raw() {
    
    
        return rawPointer;
    }
    
    
    template <class T> inline
    int Pointer<T>::count() {
        
        return *refCounter;
    }
    
    
    template <class T> inline
    T& Pointer<T>::operator [] (const size_t& index) {
    
    
        return rawPointer[index];
    }
    
    
    template <class T> inline
    T& Pointer<T>::operator * () {
    
    
        return *rawPointer;
    }
    
    
    template <class T> inline
    T& Pointer<T>::operator -> () {
    
    
        return *rawPointer
    }
    
    
    template <class T> inline
    T** Pointer<T>::operator & () {
    
    
        return &rawPointer;
    }
    
    
    template <class T> inline
    const T* Pointer<T>::raw() const {
    
    
        return rawPointer;
    }
    
    
    template <class T> inline
    const int Pointer<T>::count() const {
    
    
        return *refCounter;
    }
    
    
    template <class T> inline
    const T& Pointer<T>::operator [] (const size_t& index) const {
    
    
        return rawPointer[index];
    }
    
    
    template <class T> inline
    const T& Pointer<T>::operator * () const {
    
    
        return *rawPointer;
    }
    
    
    template <class T> inline
    const T& Pointer<T>::operator -> () const {
    
    
        return *rawPointer
    }
    
    
    template <class T> inline
    const T** Pointer<T>::operator & () const {
    
    
        return &rawPointer;
    }
    
    
    template <class T> inline
    Pointer<T>& Pointer<T>::operator = (T *ptr) {
    
    
        if (rawPointer != ptr) {
            if (*refCounter == 0)
                delete[] refCounter;
            else if (--*refCounter == 0)
                delete[] rawPointer;
            
            refCounter = new int;
            *refCounter = 1;
            rawPointer = ptr;
        }
        return *this;
    }
    
    
    template <class T> inline
    Pointer<T>& Pointer<T>::operator = (const Pointer<T>& ptr) {
    
    
        if (rawPointer != ptr) {
            if (*refCounter == 0)
                delete[] refCounter;
            else if (--*refCounter == 0)
                delete[] rawPointer;
    
    
            *refCounter = ++*ptr.refCounter;
            rawPointer = ptr.rawPointer;
        }
        return *this;
    }
    
    
    template <class T> inline
    Pointer<T>& Pointer<T>::operator ++ () {
    
    
        if (*refCounter == 0)
            delete[] refCounter;
        else if (--*refCounter == 0)
            delete[] rawPointer;
    
    
        refCounter = new int;
        *refCounter = 1;
        ++rawPointer;
        return *this;
    }
    
    
    template <class T> inline
    Pointer<T> Pointer<T>::operator ++ (int) {
    
    
        if (*refCounter == 0)
            delete[] refCounter;
        else if (--*refCounter == 0)
            delete[] rawPointer;
    
    
        refCounter = new int;
        *refCounter = 1;
        ++rawPointer;
        return Array<T>(*this);
    }
    
    
    template <class T> inline
    Pointer<T>& Pointer<T>::operator -- () {
    
    
        if (*refCounter == 0)
            delete[] refCounter;
        else if (--*refCounter == 0)
            delete[] rawPointer;
    
    
        refCounter = new int;
        *refCounter = 1;
        --rawPointer;
        return *this;
    }
    
    
    template <class T> inline
    Pointer<T> Pointer<T>::operator -- (int) {
    
    
        if (*refCounter == 0)
            delete[] refCounter;
        else if (--*refCounter == 0)
            delete[] rawPointer;
    
    
        refCounter = new int;
        *refCounter = 1;
        --rawPointer;
        return Array<T>(*this);
    }
    
    
    template <class T> 
    template <class U> inline
    Pointer<T>& Pointer<T>::operator += (const U& other) {
    
    
        if (*refCounter == 0)
            delete[] refCounter;
        else if (--*refCounter == 0)
            delete[] rawPointer;
    
    
        refCounter = new int;
        *refCounter = 1;
        rawPointer += other;
        return *this;
    }
    
    
    template <class T>
    template <class U> inline
    Pointer<T>& Pointer<T>::operator -= (const U& other) {
    
    
        if (*refCounter == 0)
            delete[] refCounter;
        else if (--*refCounter == 0)
            delete[] rawPointer;
    
    
        refCounter = new int;
        *refCounter = 1;
        rawPointer -= other;
        return *this;
    }
    
    
    template <class T>
    template <class U> inline
    Pointer<T>& Pointer<T>::operator *= (const U& other) {
    
    
        if (*refCounter == 0)
            delete[] refCounter;
        else if (--*refCounter == 0)
            delete[] rawPointer;
    
    
        refCounter = new int;
        *refCounter = 1;
        rawPointer *= other;
        return *this;
    }
    
    
    template <class T>
    template <class U> inline
    Pointer<T>& Pointer<T>::operator /= (const U& other) {
    
    
        if (*refCounter == 0)
            delete[] refCounter;
        else if (--*refCounter == 0)
            delete[] rawPointer;
    
    
        refCounter = new int;
        *refCounter = 1;
        rawPointer /= other;
        return *this;
    }
    
    
    template <class T>
    template <class U> inline
    Pointer<T>& Pointer<T>::operator %= (const U& other) {
    
    
        if (*refCounter == 0)
            delete[] refCounter;
        else if (--*refCounter == 0)
            delete[] rawPointer;
    
    
        refCounter = new int;
        *refCounter = 1;
        rawPointer %= other;
        return *this;
    }
    
    
    template <class T>
    template <class U> inline
    Pointer<T>& Pointer<T>::operator >>= (const U& other) {
    
    
        if (*refCounter == 0)
            delete[] refCounter;
        else if (--*refCounter == 0)
            delete[] rawPointer;
    
    
        refCounter = new int;
        *refCounter = 1;
        rawPointer >>= other;
        return *this;
    }
    
    
    template <class T>
    template <class U> inline
    Pointer<T>& Pointer<T>::operator <<= (const U& other) {
    
    
        if (*refCounter == 0)
            delete[] refCounter;
        else if (--*refCounter == 0)
            delete[] rawPointer;
    
    
        refCounter = new int;
        *refCounter = 1;
        rawPointer <<= other;
        return *this;
    }
    
    
    template <class T>
    template <class U> inline
    Pointer<T>& Pointer<T>::operator &= (const U& other) {
    
    
        if (*refCounter == 0)
            delete[] refCounter;
        else if (--*refCounter == 0)
            delete[] rawPointer;
    
    
        refCounter = new int;
        *refCounter = 1;
        rawPointer &= other;
        return *this;
    }
    
    
    template <class T>
    template <class U> inline
    Pointer<T>& Pointer<T>::operator |= (const U& other) {
    
    
        if (*refCounter == 0)
            delete[] refCounter;
        else if (--*refCounter == 0)
            delete[] rawPointer;
    
    
        refCounter = new int;
        *refCounter = 1;
        rawPointer |= other;
        return *this;
    }
    
    
    template <class T>
    template <class U> inline
    Pointer<T>& Pointer<T>::operator ^= (const U& other) {
    
    
        if (*refCounter == 0)
            delete[] refCounter;
        else if (--*refCounter == 0)
            delete[] rawPointer;
    
    
        refCounter = new int;
        *refCounter = 1;
        rawPointer ^= other;
        return *this;
    }
    
    
    template <class T, class U> inline
    bool operator == (const Pointer<T>& ptr, const U& other) {
    
    
        return (ptr.rawPointer == other);
    }
    
    
    template <class T, class U> inline
    bool operator != (const Pointer<T>& ptr, const U& other) {
    
    
        return (ptr.rawPointer != other);
    }
    
    
    template <class T, class U> inline
    bool operator >= (const Pointer<T>& ptr, const U& other) {
    
    
        return (ptr.rawPointer >= other);
    }
    
    
    template <class T, class U> inline
    bool operator <= (const Pointer<T>& ptr, const U& other) {
    
    
        return (ptr.rawPointer <= other);
    }
    
    
    template <class T, class U> inline
    bool operator > (const Pointer<T>& ptr, const U& other) {
    
    
        return (ptr.rawPointer > other);
    }
    
    
    template <class T, class U> inline
    bool operator < (const Pointer<T>& ptr, const U& other) {
    
    
        return (ptr.rawPointer < other);
    }
    
    
    template <class T> inline
    bool Pointer<T>::operator ! () {
    
    
        return !rawPointer;
    }
    
    
    template <class T>
    template <class U> inline
    Pointer<T>::operator U() {
    
    
        return rawPointer;
    }
    
    
    template <class T>
    template <class U> inline
    Pointer<T>::operator U*() {
    
    
        return rawPointer;
    }
    
    
    template <class T>
    template <class U> inline
    Pointer<T>::operator Pointer<U>() {
    
    
        Pointer<U> ptr;
        ptr.refCounter = refCounter;
        ptr.rawPointer = rawPointer;
        return ptr;
    }
    
    
    template <class T> inline
    std::ostream& operator << (std::ostream& os, const Pointer<T>& ptr) {
    
    
        return (os << rawPointer);
    }
    
    
    #endif // __POINTER_H
    Last edited by cmajor28; 05-10-2015 at 10:12 AM.

  14. #14
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    I overloaded all of the assignment stuff because actual pointers let you do that.
    O_o

    No. You've overloaded far too many operators.

    You should take a look at what operations are valid on native pointers.

    As for + - and such, the conversion operator takes care of those.
    No. You actually do need to write the companion operators.

    I'm looking at my code and I'm baffled, when do I need to delete the reference counter?
    Your code is problematic in numerous ways, and the majority of your problems come from not using idiomatic techniques.

    The counter may be released when the actual object is released, but you could keep the reference count around as a debugging aid in some tools.

    I think I found where...
    You haven't.

    A destructor is only called once unless you have some extraordinary bugs.

    Your code besides still has a lot of bugs.

    [Edit]
    If you toss the extraneous code, I'd be inclined to point out specific problems.

    As your code is, you have too many mistakes for me to explain them all.

    You should start small; you can implement the default constructor, value (the one taking a pointer to type from template argument) constructor, copy constructor, destructor, and a `get' method.
    [/Edit]

    Soma
    Last edited by phantomotap; 05-10-2015 at 10:37 AM.
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  15. #15
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    If I remember correctly the only operators a pointer really needs are dereference (* and -> for user defined types), equality (==), and inequality (!=). Dereference might be fairly obvious, but equality and inequality compare the contained address to another address. Like, mysmartptr<T> and another mysmartptr<T>, or mysmartptr<T> and T*. Also you probably need operator = for memory management purposes.

    The other operators, as phantomotap mentioned, do not need to be implemented, because you probably mean to use the contained type's operators instead. That being the case, you will invariably write something like *p + *q, or whatever it is. Smart pointers also don't normally double as iterators, where you have other operators like [], ++ or --.
    Last edited by whiteflags; 05-10-2015 at 11:09 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. When to use smart pointers?
    By Neo1 in forum C++ Programming
    Replies: 1
    Last Post: 04-15-2012, 10:53 AM
  2. Replies: 7
    Last Post: 08-04-2009, 11:40 AM
  3. unsure about auto/smart pointers
    By l2u in forum C++ Programming
    Replies: 16
    Last Post: 07-13-2007, 12:55 PM
  4. weak pointers and use_count smart pointers
    By Mario F. in forum C++ Programming
    Replies: 2
    Last Post: 07-29-2006, 07:54 AM
  5. Use Count smart pointers. Need clarification
    By Mario F. in forum C++ Programming
    Replies: 8
    Last Post: 06-26-2006, 03:07 PM