Advertisement

Weird C++ type conversion problem (HARD)...

Started by September 03, 2000 03:08 PM
74 comments, last by Dire.Wolf 24 years, 3 months ago
Updated smartptr template class:

        #ifndef __SMARTPTR_H#define __SMARTPTR_Htemplate<class T>class smartptr{    public:	// class typedefs and constants	typedef T value_type;			// constructor	explicit smartptr(value_type* p = 0) : ptr(p), count(new long(1))	{	}        	// copy constructor	smartptr(const smartptr<value_type>& rhs) : ptr(rhs.ptr), count(rhs.count)	{	    ++(*count);	}        	// assignment operator for pointers	template<class new_value_type>	smartptr<value_type>& operator =(new_value_type* rhs)	{	    if(ptr == rhs)	    {		return *this;	    }				    _free();            // provide compile time type checking (looks ugly but it works)	    new_value_type *t2 = 0;	    value_type     *t1 = t2;            	    ptr   = rhs;	    count = new long(1);	    return *this;	}        	// assignment operator for smartptr's	template<class T2>	smartptr<T>& operator =(smartptr<T2>& rhs)	{	    if(this == &rhs)	    {		return *this;	    }	    // release smartptr	    _free();				    // provide compile time type checking (looks ugly but it works)	    new_value_type *t2 = 0;	    value_type     *t1 = t2;				    // assign the new smartptr	    assign_smartptr<value_type, new_value_type>(&count, 			                                            reinterpret_cast<void**>(&ptr),														&rhs);	    return *this;	}        	// destructor	~smartptr()	{	    _free();	}        	// returns the internal type as a reference	value_type& operator *()	{	    return *ptr;	}        	// returns a pointer to the internal type	value_type* operator->()	{	    return static_cast<value_type*>(ptr);	}        			// returns the current reference count for the object	// being pointed to	long refcount() const	{	    return *count;	}        	// release the smartptr	void release()	{	    _free();	}            private:	// called to decrement reference count and free memory if necessary	void _free()	{	    if(--(*count) == 0)	    {		delete ptr;		delete count;	    }	    // safety first	    ptr   = 0;	    count = 0;	}         	// give friendship to non-member template function	template<class value_type, class new_value_type>	friend void assign_smartptr(long** count, void** dest, smartptr<new_value_type>* src);        			// class data members	T     *ptr;	long  *count;};template<class value_type, class new_value_type>inline void assign_smartptr(long** count, void** dest, smartptr<new_value_type>* src){    *dest  = src->ptr;    *count = src->count;    ++(**count);}#endif    


I'm still looking for someone to test this code on another compiler (and platform).

Thanks again,

- Dire Wolf
direwolf@digitalfiends.com

Edited by - Dire.Wolf on September 7, 2000 2:30:39 PM

Edited by - Dire.Wolf on September 7, 2000 2:31:45 PM
[email=direwolf@digitalfiends.com]Dire Wolf[/email]
www.digitalfiends.com
quote:
Where I work, we''ve rejected _lots_ of potential programmers simply because they can''t see outside of the C++ box. Its really terrible. They don''t understand the significance of memory allocation, the significance of easy to read code, or the significance of _few_ layers of abstraction.


quote: Original post by Stoffel
Is this really true? I''d venture to say you''ve let some great people go. Personally, I started on embedded systems in ASM, then in C. I do lots of graphics now, which is why I hang out here--many times my problems overlap with game designers. That and I''m a hobbyist. But let me tell you I''m firmly rooted in the world of OO C++ now. There''s simply no faster way to develop code.


Yes. These are ideas/concepts/mentalities that are extremely hard to teach w/o a large upfront investment that many companies simply do not have the resources to provide or afford.

OO and C++ are two completely different entities: One is a methodology for designing applications; the other is a tool used to implement a particular design. OO isn''t necessarily the best approach to designing, let''s say, a parser. It has its strengths and weaknesses, as to all programming paradigms.

I have to agree with Dave here: (ab)using C++ w/o an intimate knowledge of the translation from code to microcode is a dangerous beast.

MSN
Advertisement
quote:
also forgot to check for self-assignment in both operator=


Another good reason to re-write op= so that a check for self assignment isn''t needed is that it''s not exception safe. If creating the new pointer fails (either by the ctor or operator new throwing), you''ve already deleted the old pointer. So the auto pointer is now broken, and when it goes out of scope it''s dtor will try to delete the pointer that''s already been deleted which on many system would lead to an access violation (bang!). The best way to do it is assign to a temp pointer, then only release the old one once you''ve got a new ready to assign (a dtor should never throw, and a pointer assignment can''t).

Someone mentioned Effective C++ (and more) earlier in this thread, although it does say you should check for self assignment there are a lot reason why it''s better to change op= so you don''t need to. Exceptional C++ is a good book about this kind of thing, and it''s a good book to read after Effective C++.

quote:
void _free()


I know it''s ok to start a name with an underscore as long as it''s followed by a lower case letter, but I''d still try to avoid it
quote:
I have to agree with Dave here: (ab)using C++ w/o an intimate knowledge of the translation from code to microcode is a dangerous beast.


How can you possibly know what microcode an optimizing compiler will produce? I have never known anyone in my department to say or think, "Gee, I wonder what microcode this statement will produce...". The key to any language is to know how to use it properly.

Programming languages are just interfaces that we use to generate microcode - nothing more and nothing less. I do not have to know what opcodes my compiler spits out for a various routine - I dont care. If I''m worried about speed then I''ll look at the ASM code but over all you do not need to know the microcode your COMPILER produces to use it. If your statement was true we''d might as well code in assembly and forget everything else.

Don''t get me wrong, I''m not knocking you but I completely disagree with your statement.

- Dire Wolf
direwolf@digitalfiends.com
[email=direwolf@digitalfiends.com]Dire Wolf[/email]
www.digitalfiends.com
Thanks for the tip Wilka. I do own Effective C++ (by Scott Myers) and Exceptional C++ (which I haven''t read in awhile).

You bring up a great point about exception safety and it is something that I''ll have to look into.

Now, regarding your dislike for the underscore I''ve only recently started getting into the habit of underscoring all my private functions. Since anything in a class is in its own ''namespace'' there is little chance of conflicting with Microsoft''s naming conventions

Still, I must admit I''m not sure if I''m overly keen on it...

Thanks.

- Dire Wolf
direwolf@digitalfiends.com
[email=direwolf@digitalfiends.com]Dire Wolf[/email]
www.digitalfiends.com
quote:

How can you possibly know what microcode an optimizing compiler will produce? I have never known anyone in my department to say or think, "Gee, I wonder what microcode this statement will produce...". The key to any language is to know how to use it properly.



Hmm... seems my little quote was slightly misinterpreted. Here''s the expanded version:

Going from C to ASM is pretty damn easy; the mapping is explicit and easy to understand. Going from C++ to ASM is HARD. Period. (virtually all) C++ compilers usually go form C++ -> C -> ASM, but even the translation from C++ to C is hard to understand and appreciate. Such knowledge makes it easier to grok what exactly happens in a given line of C++ code.

So, basically, try to listen to Dave; he knows what he''s talking about.

MSN
Advertisement
One question Wilka, nowhere in either of my operator= functions do I use new or require a ctor. Now you''ve got me wondering. Could you possibly provide me an example of what you mean?

Thanks in advance,

- Dire Wolf
direwolf@digitalfiends.com
[email=direwolf@digitalfiends.com]Dire Wolf[/email]
www.digitalfiends.com
I have no problem listening to Dave or you but I will not stop using C++ language features, OOA/D or the STL just because C is more simplistic to understand/use.

BTW As far as I know it is very unlikely that C can be optimized to perform better than C++.

- Dire Wolf
direwolf@digitalfiends.com
[email=direwolf@digitalfiends.com]Dire Wolf[/email]
www.digitalfiends.com
I had quick look over the code. Here''s a few things for you (feel free to tell me to shut up )

quote:
value_type* operator->()
{
return static_cast(ptr);
}


Why the static cast? ''ptr'' already is a ''value_type*'', and the static_cast makes it look like you need to do some kind of conversion.

const versions of operator * and operator-> would be handy, along with a way to get the pointer so you don''t need to do "&*ptr", the standard library uses .get() so you might as well do the same.

quote:
void release()


Does a release function make much sense on a reference counted smart pointer? If I was using a smart pointer with a release function, I''d expect it to give me the old pointer without deleting it (the way std::auto_ptr does), but you can''t really do that in nice way when the pointer is reference counted. Also you can''t be sure that release will actually delete the pointer, so I''d probably skip this function. If you want to be able to make the pointer point to nothing, assigning it to NULL would do the job.

Also in your getting functions (op * and op ->), it might be a good idea to assert the pointer first, so you''ll catch any attempts to access a NULL pointer (but don''t assert get, since it''ll probably be used inside an if to see if it points to anything).

quote:
#ifndef __SMARTPTR_H
#define __SMARTPTR_H


I missed this in my last post You should probably change this to SMARTPTR_H_INCLUED or something, a leading double underscore isn''t a valid name for anything in C++ (and maybe C, but I''m not sure on that one) unless your implementing the standard library, or a compiler + libs.

quote:
Wilka:
...it goes out of scope it''s dtor will try to delete the pointer that''s already been deleted


Didn''t you look at the code you fool? It sets the pointer to NULL in _free, so it''s ok to delete it. But I agree that it''s still a bad idea.
quote:
Didn''t you look at the code you fool? It sets the pointer to NULL in _free, so it''s ok to delete it. But I agree that it''s still a bad idea.


Didn''t you? There''s no new or ctor in op=, it just makes a copy of the pointer and ups the ref count. You must be confused with that clone_ptr you where working on the other day

Who''s the fool now?

This topic is closed to new replies.

Advertisement