C Board  

Go Back   C Board > General Programming Boards > C++ Programming

Reply
 
LinkBack Thread Tools Display Modes
Old 01-12-2010, 04:49 PM   #1
Mysterious C++ User
 
Elysia's Avatar
 
Join Date: Oct 2007
Posts: 16,078
Assignment issues

After the last problem, I encountered another.
Continuing on the shared pointer, I cannot assign the right-hand side m_ptr to the left-hand side because it's a templated-type pointer (see code).
So, I wrapped the pointer in a struct, yet I still cannot seem to get it right. I was hoping anyone with some good eyes or some free time could help me with it.

Minimal code snippet:
Code:
#ifndef MAD_SHARED_PTR_175451_H
#define MAD_SHARED_PTR_175451_H

#ifndef NULL
#define NULL 0
#endif
const int nullptr = NULL;
#include <assert.h>

class nullptr_t {};

template<int Bits> class ptr_thread_dangerous
{
};


class Derived;

template<typename T, template<int> class thread_safety = ptr_thread_dangerous, int Bits = 32> class mad_shared_ptr
{
protected:
	template<typename T, int Bits> struct sptr
	{

	};

	template<typename T, int Bits> class sptr_wrapper
	{
	public:
		sptr_wrapper(sptr<T, Bits>* p): m_p(p) {}
		/*template<typename OtherT> */sptr_wrapper& operator = (const sptr_wrapper<Derived, 32>& rhs)
		{
			m_p->p = rhs.p;
			m_p->RefCount = rhs.RefCount;
			m_p->pDeleter = rhs.pDeleter;
		}

	protected:
		sptr<T, Bits>* m_p;
	};

	typedef sptr<T, Bits> ptr_t;

public:
	mad_shared_ptr(): m_ptr(nullptr) { }

	template<typename Other> mad_shared_ptr(Other* p): m_ptr(nullptr) { *this = p; }

	template<typename Other> mad_shared_ptr(const mad_shared_ptr<Other>& rhs): m_ptr(nullptr) { *this = rhs; }

	template<typename Other> mad_shared_ptr& operator = (const mad_shared_ptr<Other>& rhs)
	{
		m_ptr = rhs.m_ptr;
		return *this;
	}

protected:
	
	sptr_wrapper<T, Bits> m_ptr;

	template<typename Other, template<int> class thread_safety, int Bits> friend class mad_shared_ptr;
};

#endif // MAD_SHARED_PTR_175451_H
Test code:
Code:
#include <... mad_shared_ptr.h>

class Base {};
class Derived: public Base {};

int main()
{
	mad_shared_ptr<Base> p;
	mad_shared_ptr<Derived> p2 = new Derived();
	p = p2;
}
And the error would be:
1>error C2679: binary '=' : no operator found which takes a right-hand operand of type 'const mad_shared_ptr<T>::sptr_wrapper<T,Bits>' (or there is no acceptable conversion)
1> with
1> [
1> T=Derived,
1> Bits=32
1> ]
1> could be 'mad_shared_ptr<T>::sptr_wrapper<T,Bits> &mad_shared_ptr<T>::sptr_wrapper<T,Bits>::opera tor =(const mad_shared_ptr<T>::sptr_wrapper<Derived,32> &)'
1> with
1> [
1> T=Base,
1> Bits=32
1> ]
1> or 'mad_shared_ptr<T>::sptr_wrapper<T,Bits> &mad_shared_ptr<T>::sptr_wrapper<T,Bits>::opera tor =(const mad_shared_ptr<T>::sptr_wrapper<T,Bits> &)'
1> with
1> [
1> T=Base,
1> Bits=32
1> ]
1> while trying to match the argument list '(mad_shared_ptr<T>::sptr_wrapper<T,Bits>, const mad_shared_ptr<T>::sptr_wrapper<T,Bits>)'
1> with
1> [
1> T=Base,
1> Bits=32
1> ]
1> and
1> [
1> T=Derived,
1> Bits=32
1> ]
Basically it's saying it can't find an assignment operator that takes sptr_wrapper<Base, 32> (which the lhs should be, and is, according to the error) and a sptr_wrapper<Derived, 32> (the very exact operator I tried adding).

If anyone spots a problem, I'd be grateful for any help.
__________________
Using: Microsoft Windows™ 7 Professional (x64), Microsoft Visual Studio™ 2010 Ultimate, C++0x
"Thanks Elysia. You're a programming master! How the hell do you know every thing?"
"Thanks for all your help. It's obvious yall really know what you're talking about when it comes to OOP/C++ stuff."
Quoted... at least once.
Quote:
Originally Posted by cpjust
If C++ is 2 steps forward from C, then I'd say Java is 1 step forward and 2 steps back.
Elysia is offline   Reply With Quote
Old 01-12-2010, 05:15 PM   #2
The larch
 
Join Date: May 2006
Posts: 3,333
Firstly you have lots of problems shadowing template parameters.

But then the problem still remains unless I just lift the nested classes out of the mad_shared_ptr class.
__________________
I might be wrong.

Quote:
Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
Quoted more than 1000 times (I hope).
anon is offline   Reply With Quote
Old 01-12-2010, 05:23 PM   #3
Mysterious C++ User
 
Elysia's Avatar
 
Join Date: Oct 2007
Posts: 16,078
Ah, I wonder why it works if I move them outside?
__________________
Using: Microsoft Windows™ 7 Professional (x64), Microsoft Visual Studio™ 2010 Ultimate, C++0x
"Thanks Elysia. You're a programming master! How the hell do you know every thing?"
"Thanks for all your help. It's obvious yall really know what you're talking about when it comes to OOP/C++ stuff."
Quoted... at least once.
Quote:
Originally Posted by cpjust
If C++ is 2 steps forward from C, then I'd say Java is 1 step forward and 2 steps back.
Elysia is offline   Reply With Quote
Old 01-12-2010, 05:38 PM   #4
Guest
 
Sebastiani's Avatar
 
Join Date: Aug 2001
Posts: 5,249
Also:

1) The code for 'sptr' in your example is incomplete
2) How exactly does class 'Derived' tie into 'mad_shared_ptr'?
3) 'mad_shared_ptr' has no assignment operator for a pointer to 'T'.
4) The purpose of 'sptr_wrapper' is unclear. Can you explain that? Further, where is it supposed to get a pointer to an 'sptr', anyway?
5) Template functions expecting another type of 'mad_shared_ptr' should forward *all* of the template parameters - not just the first one.
6) Your back to the same problem you had earlier, this time with 'sptr_wrapper' (only now in a more complicated context). Namely, a mad_shared_ptr<T, thread_safety, Bits>::sptr_wrapper<T2, Bits2> with different parameters will, of course, yield a completely different type, so the protected qualifier prevents access.
7) The idea of assigning, say, a mad_shared_ptr< float > to a mad_shared_ptr< string > doesn't even really make sense. How is that supposed to work?

Lot's of confusing issues, IMO. Maybe you could describe more clearly what you're wanting to do?
Sebastiani is offline   Reply With Quote
Old 01-13-2010, 05:06 AM   #5
Mysterious C++ User
 
Elysia's Avatar
 
Join Date: Oct 2007
Posts: 16,078
Quote:
Originally Posted by Sebastiani View Post
1) The code for 'sptr' in your example is incomplete
3) 'mad_shared_ptr' has no assignment operator for a pointer to 'T'.
Because this is a minimal code example. The real code does not have these issues.

Quote:
2) How exactly does class 'Derived' tie into 'mad_shared_ptr'?
Because it's a test to get it working right. Will remove when it works fine.


Quote:
4) The purpose of 'sptr_wrapper' is unclear. Can you explain that? Further, where is it supposed to get a pointer to an 'sptr', anyway?
Look at sptr. It has two template arguments: T and Bits.
This structure contains the actual reference counting, which is shared among all similar pointers.
Hence, in the assignment operator, I would need to duplicate the pointer address from the rhs to the lhs.
But that's impossible since sptr<Base, 32> != sptr<Derived, 32>.
What do we do then? We need a function that makes it possible to assign the rhs to lhs if and only if it's possible to assign rhs.m_ptr->p to lhs.m_ptr->p (the actual pointee it's encapsulating). This should work if rhs's pointer type is derived from lhs's pointer type.
Creating a global assignment operator is not possible, so I made a wrapper so that I could overload operator = instead.


Quote:
5) Template functions expecting another type of 'mad_shared_ptr' should forward *all* of the template parameters - not just the first one.
Not 100% sure what you mean.

Quote:
6) Your back to the same problem you had earlier, this time with 'sptr_wrapper' (only now in a more complicated context). Namely, a mad_shared_ptr<T, thread_safety, Bits>::sptr_wrapper<T2, Bits2> with different parameters will, of course, yield a completely different type, so the protected qualifier prevents access.
Yes, but we solved that with friends earlier, didn't we? Yes, we did.

Quote:
7) The idea of assigning, say, a mad_shared_ptr< float > to a mad_shared_ptr< string > doesn't even really make sense. How is that supposed to work?
It does not.
However, the idea is to use the compiler as a tool here.
In the end, it should be assigning a string* to a float* and obviously that won't work.
But if we assign a mad_shared_ptr<Derived> to a mad_shared_ptr<Base>, then in the end we should get an assignment of Derived* to Base*.
This is the idea.

Quote:
Lot's of confusing issues, IMO. Maybe you could describe more clearly what you're wanting to do?
Basically, what I need is what I described above.
I need to assign a mad_shared_ptr<Derived> to a mad_shared_ptr<Base>.
I would be happy to post the full code, that you may examine it.
You should be aware that it does rely on boost. Although I could make efforts to reduce that dependancy.
__________________
Using: Microsoft Windows™ 7 Professional (x64), Microsoft Visual Studio™ 2010 Ultimate, C++0x
"Thanks Elysia. You're a programming master! How the hell do you know every thing?"
"Thanks for all your help. It's obvious yall really know what you're talking about when it comes to OOP/C++ stuff."
Quoted... at least once.
Quote:
Originally Posted by cpjust
If C++ is 2 steps forward from C, then I'd say Java is 1 step forward and 2 steps back.
Elysia is offline   Reply With Quote
Old 01-13-2010, 08:03 AM   #6
Guest
 
Sebastiani's Avatar
 
Join Date: Aug 2001
Posts: 5,249
Quote:
Because this is a minimal code example. The real code does not have these issues.
Okay, I see.

Quote:
Because it's a test to get it working right. Will remove when it works fine.
Ah, okay. At any rate, it doesn't seem to help the situation any, so it may as well just be removed altogether.

Quote:
Look at sptr. It has two template arguments: T and Bits.
This structure contains the actual reference counting, which is shared among all similar pointers.
Hence, in the assignment operator, I would need to duplicate the pointer address from the rhs to the lhs.
But that's impossible since sptr<Base, 32> != sptr<Derived, 32>.
What do we do then? We need a function that makes it possible to assign the rhs to lhs if and only if it's possible to assign rhs.m_ptr->p to lhs.m_ptr->p (the actual pointee it's encapsulating). This should work if rhs's pointer type is derived from lhs's pointer type.
Creating a global assignment operator is not possible, so I made a wrapper so that I could overload operator = instead.
Hmm, still a bit confused on that one...

Quote:
Not 100% sure what you mean.
Well, for example, consider:

Code:

template < typename A, typename B = int, typename C = int >
struct foo
{    };

template < typename A >
void bar( foo< A > const& )
{    }

int main( void )
{
    bar( foo< int, double, double >( ) );
}
Invoking 'bar' forces the compiler to forward the default template parameters, so it fails to compile.

Quote:
Yes, but we solved that with friends earlier, didn't we? Yes, we did.
True, but then you should probably incorporate that into your example, so that we know that it isn't an issue.

Quote:
It does not.
However, the idea is to use the compiler as a tool here.
In the end, it should be assigning a string* to a float* and obviously that won't work.
But if we assign a mad_shared_ptr<Derived> to a mad_shared_ptr<Base>, then in the end we should get an assignment of Derived* to Base*.
This is the idea.
I see. But wouldn't it be sufficient to just ensure that a mad_shared_ptr<Base> is used, since that should accept a pointer to a Derived?

Quote:
Basically, what I need is what I described above.
I need to assign a mad_shared_ptr<Derived> to a mad_shared_ptr<Base>.
I would be happy to post the full code, that you may examine it.
You should be aware that it does rely on boost. Although I could make efforts to reduce that dependancy.
In this case, yes, I think the complete code would be most helpful.
Sebastiani is offline   Reply With Quote
Old 01-13-2010, 12:55 PM   #7
Mysterious C++ User
 
Elysia's Avatar
 
Join Date: Oct 2007
Posts: 16,078
I took the liberty of trying another approach.
I still get the pesky access errors, however. Don't know if it will yield more errors beyond what I get and if any linker errors.
Anyway, I did promise the code so you could see what's going on, so here it is:
Code:
#ifndef MAD_SHARED_PTR_175451_H
#define MAD_SHARED_PTR_175451_H

#ifndef NULL
#define NULL 0
#endif
const int nullptr = NULL;
//#include <boost/cstdint.hpp>
#include <memory>
#include <assert.h>

namespace boost
{
	typedef unsigned long   uint32_t;
	typedef unsigned long long uint64_t;
}

class nullptr_t {};

template<typename T> T* mad_ptr_clone(const T* pOld) { return smad_ptr_int<T, boost::is_polymorphic<T>::value>::Clone(pOld); }

template<typename T, bool Polymorphic> struct smad_ptr_int
{
	static T* Clone(const T* pOld) { return pOld->Clone(); } // IsPolymorphic = yes
};
template<typename T> struct smad_ptr_int<T, false>
{
	static T* Clone(const T* pOld) { return new T(*pOld); } // IsPolymorphic = no
};

template<int N> struct ptr_bits { /*typedef current_amount_of_bits_not_supported rf_type;*/ };
template<> struct ptr_bits<32> { typedef boost::uint32_t rf_type; };
template<> struct ptr_bits<64> { typedef boost::uint64_t rf_type; };

#if _WIN32_WINNT >= 0x600 && WINVER >= 0x600
	#include <windows.h>

	template<int Bits> class ptr_thread_safe { };
	template<> class ptr_thread_safe<32> 
	{
	public:
		static void Increment(void* p) { InterlockedIncrement((LONG*)p); }
		static void Decrement(void* p) { InterlockedDecrement((LONG*)p); }
	};
	template<> class ptr_thread_safe<64> 
	{
	public:
		static void Increment(void* p) { InterlockedIncrement64((LONGLONG*)p); }
		static void Decrement(void* p) { InterlockedDecrement64((LONGLONG*)p); }
	};
#endif

template<int Bits> class ptr_thread_dangerous
{
public:
	template<typename T> static void Increment(T* p) { (*p)++; }
	template<typename T> static void Decrement(T* p) { (*p)--; }
};

class Derived;

template<typename T, int Bits> struct sptr;
template<typename T, int Bits, typename OtherT> sptr<T, Bits>* CastToSptrT(sptr<OtherT, Bits>* p)
{
	T* pTest = p->p; // Test if Other is implicitly convertable to T.
	return (sptr<T, Bits>*)p;
}
	
template<typename T, int Bits> struct sptr
{
	template<typename T> class deleter_base { public: virtual void destroy(T* p) = 0; };
	template<typename T, typename deleter_t> class deleter: public deleter_base<T>
	{
	public:
		deleter(deleter_t delete_fnc): m_delete_fnc(delete_fnc) { }
		virtual void destroy(T* p) { m_delete_fnc(p); }

	private:
		deleter_t m_delete_fnc;
	};

	sptr(): p(nullptr), RefCount(0), pDeleter(nullptr) { }

	T* p;
	typename ptr_bits<Bits>::rf_type RefCount;
	deleter_base<T>* pDeleter;

	template<typename T, int Bits, typename OtherT> friend sptr<T, Bits>* CastToSptrT <> (sptr<OtherT, Bits>* p);
};

//template<typename T, int Bits> class sptr_wrapper
//{
//public:
//	sptr_wrapper(sptr<T, Bits>* p): m_p(p) {}
//	template<typename OtherT> sptr_wrapper& operator = (const sptr_wrapper<OtherT, Bits>& rhs)
//	{
//		assert(m_p);
//		assert(rhs.m_p);
//		m_p->p = rhs.m_p->p;
//		m_p->RefCount = rhs.m_p->RefCount;
//		m_p->pDeleter = rhs.m_p->pDeleter;
//	}
//
//	sptr<T, Bits>* operator -> () { assert(m_p); return m_p; }
//
//	sptr<T, Bits>* get() { assert(m_p); return m_p; }
//	void set(sptr<T, Bits>* p) { assert(p); m_p = p; }
//
//protected:
//	sptr<T, Bits>* m_p;
//	template<typename T, int Bits> friend class sptr_wrapper;
//};

template<typename T, template<int> class thread_safety = ptr_thread_dangerous, int Bits = 32> class mad_shared_ptr
{
protected:
	typedef void (mad_shared_ptr::* bool_type)() const;

	typedef sptr<T, Bits> ptr_t;

public:
	mad_shared_ptr(): m_ptr(nullptr) { }

	template<typename Other> mad_shared_ptr(Other* p): m_ptr(nullptr) { *this = p; }

	template<typename Other, typename Deleter> mad_shared_ptr(Other* p, Deleter delete_fnc): m_ptr(nullptr)
	{
		std::auto_ptr< ptr_t::deleter_base<T> > pDeleter( new ptr_t::deleter<T, Deleter>(delete_fnc) );
		*this = p;
		m_ptr->pDeleter = pDeleter.release();
	}

	mad_shared_ptr(const mad_shared_ptr& rhs): m_ptr(nullptr) { *this = rhs; }

	template<typename Other> mad_shared_ptr(const mad_shared_ptr<Other>& rhs): m_ptr(nullptr) { *this = rhs; }

	mad_shared_ptr(const nullptr_t&): m_ptr(nullptr) { }

	~mad_shared_ptr() { DecRefCount(m_ptr); }

	bool unique() const { return (m_ptr->RefCount == 1); }

	void make_unique()
	{
		if (unique())
			return;
		
		std::auto_ptr<ptr_t> pNewPtr(new ptr_t);
		pNewPtr->p = mad_ptr_clone(m_ptr->p);
		pNewPtr->RefCount = 1;
		pNewPtr->pDeleter = m_ptr->pDeleter;
		DecRefCount(m_ptr);
		m_ptr = pNewPtr.release();
	}

	void release()
	{
		DecRefCount();
		m_p = nullptr;
		m_RefCount = nullptr;
		m_deleter = nullptr;
	}

	template<typename Other> mad_shared_ptr& operator = (Other* rhs)
	{
		if (m_ptr && rhs == m_ptr->p)
			return *this;

		ptr_t* pOldPtr = m_ptr;
		std::auto_ptr<ptr_t> pNewPtr(new ptr_t);

		pNewPtr->p = rhs;
		pNewPtr->RefCount++;
		m_ptr = pNewPtr.release();

		DecRefCount(pOldPtr);
		return *this;
	}

	mad_shared_ptr& operator = (const mad_shared_ptr& rhs)
	{
		return operator = <T>(rhs);
	}

	template<typename Other> mad_shared_ptr& operator = (const mad_shared_ptr<Other>& rhs)
	{
		if (rhs == *this)
			return *this;
		//T* pTest = rhs.m_ptr->p; // Test if Other is implicitly convertable to T.
		DecRefCount(m_ptr);
		m_ptr = CastToSptrT<T>(rhs.m_ptr);
		IncRefCount(m_ptr);
		return *this;
	}

	mad_shared_ptr& operator = (const nullptr_t&)
	{
		DecRefCount(m_ptr);
		m_ptr = nullptr;
		return *this;
	}

	T& operator * () const { assert(m_ptr); return *m_ptr->p; }
	T* operator -> () const { assert(m_ptr); return m_ptr->p; }

	template<typename rhs_t>
	friend bool operator == (const mad_shared_ptr& lhs, const mad_shared_ptr<rhs_t>& rhs)
	{
		return (lhs.m_ptr == CastToSptrT<T>(rhs.m_ptr));
	}

	template<typename rhs_t>
	friend bool operator != (const mad_shared_ptr& lhs, const mad_shared_ptr<rhs_t>& rhs)
	{
		return !(lhs == CastToSptrT(rhs));
	}

	operator bool_type() const 
	{
		return m_ptr && m_ptr->p ? &mad_shared_ptr::this_type_does_not_support_comparisons : nullptr;
	}

protected:
	void IncRefCount(sptr<T, Bits>* ptr)
	{
		thread_safety<Bits>::Increment(&ptr->RefCount);
	}

	void DecRefCount(sptr<T, Bits>*& ptr)
	{
		if (ptr == nullptr)
			return;
		thread_safety<Bits>::Decrement(&ptr->RefCount);
		if (ptr->RefCount == 0)
		{
			if (ptr->pDeleter)
				ptr->pDeleter->destroy(ptr->p);
			else
				delete ptr->p;
			delete ptr;
			ptr = nullptr;
		}
	}

	void this_type_does_not_support_comparisons() const {}

	sptr<T, Bits>* m_ptr;

	template<typename OtherT, template<int> class thread_safety, int Bits> friend class mad_shared_ptr;
};

#endif // MAD_SHARED_PTR_175451_H
__________________
Using: Microsoft Windows™ 7 Professional (x64), Microsoft Visual Studio™ 2010 Ultimate, C++0x
"Thanks Elysia. You're a programming master! How the hell do you know every thing?"
"Thanks for all your help. It's obvious yall really know what you're talking about when it comes to OOP/C++ stuff."
Quoted... at least once.
Quote:
Originally Posted by cpjust
If C++ is 2 steps forward from C, then I'd say Java is 1 step forward and 2 steps back.

Last edited by Elysia; 01-13-2010 at 12:59 PM.
Elysia is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Menu Krush C Programming 17 09-01-2009 02:34 AM
Assignment Operator, Memory and Scope SevenThunders C++ Programming 47 03-31-2008 06:22 AM
Screwy Linker Error - VC2005 Tonto C++ Programming 5 06-19-2007 02:39 PM
Help with a pretty big C++ assignment wakestudent988 C++ Programming 1 10-30-2006 09:46 PM
A mini-compilier I made stuck in an infinite loop (lots of code) dan06 C++ Programming 1 10-27-2006 01:21 PM


All times are GMT -6. The time now is 12:06 AM.


Powered by vBulletin® Version 3.8.1
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.3.2

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22