Archived

This topic is now archived and is closed to further replies.

SajberToffe

Template Delete

Recommended Posts

Hello! I have some plans for a engine. After reading through superpig''s great articles I figured that I''d need some kind of MemoryManagemanet. I didn''t want every object to have a common baseclass, rather that any created class without modification would be useable. I thought refcounting would be easiest to implement. After trial and error, I came up with this.
template<typename T>
struct Node
{
    T data;
    Node<T> * next;
};

inline void * operator new(size_t size)
{
    if(!size)size++;
    Node<unsigned int> * node = (Node<unsigned int> *)malloc(size + sizeof(Node<unsigned int>));
    node->data = 0; // References

    node->next = Registry::headNode;
    Registry::headNode = node;
    return (void*)((int)node + sizeof(Node<unsigned int>));
}

template<typename T>
void Delete(T * data)
{
    Node<unsigned int> * ptr = (Node<unsigned int> *)((int)data - sizeof(Node<unsigned int>));
    data->~T();
    free(ptr);
    //free(data) screws the memory up

}

void AddRef(void * ptr)
{    
    Node<unsigned int> * node = (Node<unsigned int> *)((int)ptr - sizeof(Node<unsigned int>));
    node->data++;
}

void Release(void * ptr)
{
    Node<unsigned int> * node = (Node<unsigned int> *)((int)ptr - sizeof(Node<unsigned int>));
    node->data--;
}
The objects would all be freed from some Registry class, no delete calls would be allowed. Now my questions are: (1)Are objects really freed when using free() on the ptr pointer? I know that the destructor is called, but is the whole memory block made free? (2)Is 2 byte too expensive for every object? There are some trouble when pointing to a arrayed object, but still... Sorry for a confusing post

Share this post


Link to post
Share on other sites
Oh yes, but I made it this way, since I need to get the size of the deleted object(planning on implementing a mem pool too), cause one can't get the size from delete(void * ptr). Anyway, the delete syntax wouldn't matter, I was going to let the GC do that job.

But is this a good aproach?

EDIT: Ahh, I'm on a LAN right now, so my mind is quite messy...

[edited by - SajberToffe on October 22, 2003 10:58:48 PM]

Share this post


Link to post
Share on other sites
What are these objects that you are reference counting? Typically, it only make sense to reference count "heavy" concrete objects, or specific references exposed by interfaces on a concrete object. Thus, you''d reference count the IPropertyCollection of some IEntity, but you wouldn''t reference count each CIntegerValue you get out from that collection, instead declaring the the CIntegerValue is live as long as the owning collection is live, using using copy semantics (likely for the integer property case).

Once you decide that you only reference count interfaces, having all interfaces derive (virtually?) from a single base interface, a la IUnknown in COM, makes reference counting mostly trivially implementable in that base class.

I also don''t like it the way you chain all your objects in a big linked list -- how would you delete an object from the list in an efficient manner? In your current version, the first object that you delte makes following the list be a crashing proposition. You need a doubly linked list (2 pointers, plus ref count) to accomplish that, and the value is dubious. Much better to hook in on the lower level and override operator new to allocate out of your own arena where you can dump allocated blocks. Then you can also easily do pooled allocations (allocate clumps of N objects at a time and dole them out 1 by 1).

Share this post


Link to post
Share on other sites
Thanks for a good reply!

I guess you''re right... The objects that are reference counted are every object that''s on the heap, stacked variables won''t cause any memory leak. Yet, to assign 8 or 12(if I changed to a doubly-linked list) bytes for every object might be unnessasary. Perhaps I''ll find a better way of doning it.

Share this post


Link to post
Share on other sites
Having a hard time with your code.

I don't get your add_ref and release functions at all
How does this

node->data++; add a reference?
Like-wise
node->data--; remove one?

Please tell me your not expecting the type T to overide ++,-- to do the reference couting for itself.
Horrid design.

If you want it to be a generic memmory manager make it generic by not enforcing anything.

I think most (if not all, but not sure) standard containers dont even force the type to be default constructible.

Personally, i would just use std::list of some smart ptr to T.

Maybe theres a way to make a custom allocator that uses boost :: pool for said list. But i never used pool so it might be more trouble than its worth

Just my 2c
Amnesty

[edited by - Amnesty on October 23, 2003 3:55:13 AM]

Share this post


Link to post
Share on other sites
The size of the allocation is the size of the object + the size of a node. The Node is placed just before the object. The Node is just containing the references, that''s the data member(data = unsigned short), and that is increased, nothing in the class. The Node contain Pointers to other allocated objects, that are linked so GC can check references.
No pointer to the object it''s refering to is required, since it''s address is just after the node.

About STL, your right... It''s just a bad habbit, but I had some trouble learning the concept of linked list when I started. I made a couple of linked lists and that has just stuck so now my own imlpementations are easy and clear to me... maby a bit faster too

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
actually pointer sizes can vary altough they can be at most sizeof(void *) * CHAR_BITS / 8 bytes.

Share this post


Link to post
Share on other sites
quote:

...cause one can't get the size from delete(void * ptr)...


Actually you can, just declare you delete-operator as

void operator delete(void *p, std::size_t size) {}

more people than you have found the need for size to be an argument of delete...

[edited by - amag on October 23, 2003 7:54:50 AM]

Share this post


Link to post
Share on other sites
That''s true... maby it''s not much of a difference anyway... perhaps I''ll stick with operator delete...

But still, I don''t know someone answered my main question. If the whole memory block is freed when freeing from the node part.

Share this post


Link to post
Share on other sites