Al een tijdje gebruik ik zelfgeschreven reference counting pointers. De relevante stukjes code daarvan heb ik hieronder geplakt. Zodra ik een object alloceer roep ik een speciale functie aan; die maakt een Resource-object, stopt daar de pointer in en geeft een ref<T> terug (die een Resource<T>* bevat). Op die manier kan ik ook weak-references maken (maar die zijn in dit verhaal niet echt van belang).
Het probleem begint echter als ik ga casten: als ik een class A heb die afstamt van B dan kan ik (zie code onder) gewoon ref<B>(a) doen (met a een ref<A>). Zoals je ziet wordt dan nog wel gecheckt of dat uberhaupt wel mag (dynamic_cast) maar vervolgens wordt de Resource<A>* domweg als Resource<B>* gebruikt. Dat dat niet netjes is weet ik ook wel, maar het werkt zo prima (waarschijnlijk omdat dynamic_cast<B*>(a) == a toevallig) en het heeft ook voordelen: de ref hoeft niet te weten wat het type van het originele object was en de ref blijft zo groot als een pointer (die dingen worden overal gebruikt dus moeten klein blijven).
Echter, bij multiple inheritance gaat dit goed fout. Ik zoek dus een manier om deze reference-counted pointers daarvoor geschikt te maken, zonder de ref<T>'s groter te maken of de reference count in het object zélf op te slaan (dan kan ik weer heel lastig weak references maken...). Een oplossing die ik zelf al had bedacht is om in Resource een Object* op te slaan (alle objecten stammen daarvan af) en in ref<T>::operator-> altijd een dynamic_cast<T>(_res->object) te doen. Ik vermoed alleen dat dat érg traag gaat zijn...
Het probleem begint echter als ik ga casten: als ik een class A heb die afstamt van B dan kan ik (zie code onder) gewoon ref<B>(a) doen (met a een ref<A>). Zoals je ziet wordt dan nog wel gecheckt of dat uberhaupt wel mag (dynamic_cast) maar vervolgens wordt de Resource<A>* domweg als Resource<B>* gebruikt. Dat dat niet netjes is weet ik ook wel, maar het werkt zo prima (waarschijnlijk omdat dynamic_cast<B*>(a) == a toevallig) en het heeft ook voordelen: de ref hoeft niet te weten wat het type van het originele object was en de ref blijft zo groot als een pointer (die dingen worden overal gebruikt dus moeten klein blijven).
Echter, bij multiple inheritance gaat dit goed fout. Ik zoek dus een manier om deze reference-counted pointers daarvoor geschikt te maken, zonder de ref<T>'s groter te maken of de reference count in het object zélf op te slaan (dan kan ik weer heel lastig weak references maken...). Een oplossing die ik zelf al had bedacht is om in Resource een Object* op te slaan (alle objecten stammen daarvan af) en in ref<T>::operator-> altijd een dynamic_cast<T>(_res->object) te doen. Ik vermoed alleen dat dat érg traag gaat zijn...
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
| template< typename T > class Resource { friend class ref<T>; public: Resource(T*) {...} ~Resource() {...} inline void AddReference() {...} inline void DeleteReference() {...} protected: T* _object; long _rc; long _weakrc; }; template<typename T> class ref { friend class Resource<T>; public: inline ref(intern::Resource<T>* rx=0) {...} inline ref(const ref<T>& org) {...} template<typename RT> inline ref(const ref<RT>& org) { if(org._res==0) { _res = 0; } else { T* rt = dynamic_cast<T*>(org._res->_object); if(rt==0) throw BadCastException(); // Dit is natuurlijk smerig... maar het werkt tot op zekere hoogte // Merk op dat org._res een Resource<RT>* is.... _res = reinterpret_cast<Resource<T>* >(org._res); if(_res!=0) { _res->AddReference(); } } } inline ~ref() {...} inline T* operator->() { if(_res->_object==0) throw NullPointerException(); return _res->_object; // Omdat _res een Resource<T>* is, is _res->_object hier een T* } private: Resource<T>* _res; }; |
[ Voor 0% gewijzigd door MisterData op 28-12-2007 14:09 . Reden: _data en _object zijn hetzelfde ]