Advertisement

cow pointers

Started by September 09, 2000 05:33 PM
12 comments, last by null_pointer 24 years, 3 months ago
Yeah, that''s the problem with copying.

I figured out how to do it. Here''s what I''ve got so far:


namespace deallocation {

template &lttypename type>
struct heap
{ void deallocate(type* resource) { delete( resource ); } };

template &lttypename type>
struct stack
{ void deallocate(type* resource) { resource->~type(); } }

};

namespace duplication {

template &lttypename type, typename second_type = type>
struct heap
{ type* duplicate(second_type* resource) { return( new type(*resource) ); } };

// for stack, implement something special with placement new...

};



The handle code simply calls those functions on its members. duplication::heap is only used by copy_handle. If the user of the handle classes wants to use handles of different classes in a hierarchy interchangably, he has to declare the proper deallocator as the base class, and should use virtual destructors. Also, the duplicator class as a templated struct cannot be used interchangably with different parameters for the "type" template parameter, so copying is always safe.

About the array stuff, I disallowed any use of delete[] as a deallocator. Remember, if the user wants an array, he/she should use vector instead of a handle (it''s essentially the same thing, but vector is much better suited and does a lot more). Nothing prevents the user from having a handle to a vector or list, or whatever container type he/she wishes.

BTW, the stack duplicator is for placement new to "emulate" the stack with a set chunk of heap memory. I thought it might be a very useful feature for holding matrices/vertices/etc. If anyone has any suggestions on how to do that, I''d be grateful!

Whew! finally done!

Thanks Wilka!



- null_pointer
Sabre Multimedia
quote:
Wilka:
...could cause you problems, template types aren''t polymorphic.


Well I''ve got a way to get around that problem now, you just overload the function with two types. T* and *. e.g.

template<class T>void foo(T*, void*){	cout << "void*" << endl;}template<class T>void foo(T*, int*){	cout << "int*" << endl;} 


You leave T as a template parameter, but you add another overload to the function for the base type that you care about (int in this case). The default is void* so it works with all types if there isn''t a better match. Then you make the class that uses this function pass in it''s parameter twice - the first one (the template) will be an exact match, so the function that has the best match for the second parameter is chosen.

You probably done care for this project, but it might come in handy some other time
Advertisement
That''s a good idea, but it creates some other problems. First, to use the smart_handle class with a class hierarchy, the pointer must be stored as a pointer to the base class:


smart_handle&ltbase> p1 = new base;
smart_handle&ltbase> p2 = new derived;

p1 = p2; // ok since both are base



If you''re using it polymorphically, you don''t need the exact pointer type - a pointer to the base will do fine. I have to do this since VC refuses to accept the templated conversion operators... (see Dire.Wolf''s example) Unfortunately, since all pointers are the same type, overloading the duplicators doesn''t work, so I decided to use the method you posted earlier - a polymorphic duplicator:


struct polymorphic
{ base* const duplicate(const base* const resource) { return( resource->duplicate() ); } };



Which of course requires that a duplicate() function be implemented in all classes and at least declared in the base.

Thanks for all of your help Wilka!


- null_pointer
Sabre Multimedia
quote:
If you''re using it polymorphically, you don''t need the exact pointer type - a pointer to the base will do fine.


Yes, but sometimes you could might want to store a CWeapon instead of a CEntity and if you use the template only method you''d need to add a specialisation for CWeapon and any other CEntity based class you want to store. But if you have the Clone() function in CEntity, you only need to provided a CEntity overload for the duplication function.

quote:
I decided to use the method you posted earlier - a polymorphic duplicator


The advantage of adding an overload for the function is that you can still copy classes that don''t provided a duplicate(). You just add an overloaded function for the class you want to copy. If you make the default use the duplicate function, you wont need to change any existing code that uses the handle.

After typing that I''ve just realised a problem, the return type of the overloaded function wont match that of the stored type (and vc doesn''t support variant return types of virtual functions). So you''d need to add a static_cast when you call the overloaded function which could cause a problem (but it probably wont, I just can''t think of way to make sure it wont be a problem).

There''s not much point in changing your handle class now, cos it''s working fine But it''s generally a good idea for templates to place as few constraints of the contained types as possible.

This topic is closed to new replies.

Advertisement