Re: Is there a design pattern for holding the same pointers in many arrays?
Hakusa@gmail.com wrote:
Is there a design pattern for holding the same pointers in many
arrays? The obvious answer is to use a smart pointer, but i am and
there's more to it.
I'm making a real-time graphical application (video game) and i want a
list of every graphical object, a list of every circular object,
square object, every physical object, etc. Many applications even have
so-called buckets, which ensure that certain objects are updated
before others.
I guess the answer is performance, but still I'll ask the question: Why do
you need these lists? You could store the objects in a single list and when
you want to access all circular objects, you visit every object with an
according visitor (look up "visitor pattern" aka "double dispatch") that
does nothing for non-circular objects.
Every time a new list is added, code complexity grows. If i want to
create an object of type X, i currently have a function similar to:
template< typename T >
T* spawn() {
T* x = new T;
graphicalObjects.push_back( std::shared_ptr<T>(t) );
return x;
}
and it works fine, assuming there is only one list.
This is one of the worst mixtures of smart and raw pointers I have ever
seen. You should definitely return the smart pointer instead:
template<typename T>
shared_ptr<T> spawn()
{
shared_ptr<T> res(new T);
graphicalObjects.push_back(res);
return res;
}
Note that if you are using raw pointers anyway, you can also completely drop
the smart pointers. If maintaining the reference counters imposes too much
overhead, this can be an actual alternative, even though it requires lots
of manual care. Another alternative would be using a smart pointer that
with an object type that contains an embedded reference counter, which
provides better behaviour concerning the cache. Also, boost at least has a
make_shared function which avoids some of the allocation overhead for the
ref counter, I believe.
If i have many lists, how can this spawn function figure out what lists
to put it in?
I suppose many would answer that it depends on how class X is defined,
but that is liable to change based on the solution to this problem.
The only restraint is that i have a base class, B, and everything
inherits from that.
I'd suggest the visitor pattern again. Another option is that you pass a
reference to the "environment" to the objects' ctor (or a separate init
function), and they add themselves to the according lists there.
The other question is how to handle removing an object from each list
it's in.
I'd do it similarly to how you added it, either using a visitor or a virtual
function that knows what lists to delete the object from. Of course, you
can't use the destructor, because the object won't be destroyed until
before it was deleted from those lists. A way around this would be the use
of weak_ptr, which is a shared_ptr without the ownership, i.e. it
automagically goes zero when the last shared_ptr is destroyed.
Currently, my one-list solution for shape-detection is to have a pure
virtual function, B::shape_data(), that is defined by a parent of X
like SquareData or CircleData, though this is not a parent of B. i.e.:
struct Shape {};
struct CircleData : Shape { float radius; };
struct B { virtual Shape& shape_data() };
struct X : B, CircleData {
X() { radius = SOME_CONST; }
Shape& shape_data() { return *this; }
};
[...] Of course, this is only a solution for shape detection, not
the buckets or any other sort of feature detection. And having
multiple lists would make this unnecessary (as there'd be no
double dispatch).
In conclusion, is there a design pattern for this? Or is there a way
to do what i'm already doing, but better? I thought i could make an
object that stores a way of identifying an object in every list, but
if i can't do that in a functional C way, how can i in an OOP C++ way?
What are you doing with those lists? The answer to your question probably
depends on that. If all you do is e.g. first draw all circular objects,
then draw all rectangular objects etc, you could as well implement a
visitor that draws the object according to its type. Or, you could go the
OOP way and use a virtual function.
Good luck!
Uli
--
Sator Laser GmbH
Gesch??ftsf??hrer: Thorsten F??cking, Amtsgericht Hamburg HR B62 932
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]