динамические структуры данных
От: Аноним  
Дата: 27.06.08 23:26
Оценка:
Уважаемые эксперты. У меня вопрос по ликбезу.
Если я создаю некоторую динамическую структуру данных, например бинарное дерево в чистом С, то мне придётся либо реализовать дерево для каждого типа отдельно (int, char, char*, struct {...} и т.д.) либо реализовать дерево для void*. Есть ли другие возможности?

Во втором случае возникает вопрос: если я помещаю в дерево элемент (функция insert_item), каковы мои действия? Например, создаем копи объекта, который хотим иметь в дереве и помещаем её (копию) в него (дерево). Но, как тогда узнать размер объекта? Особенно если это строки? (делать константу МАХ_SIZE?)

Если просто сохраням адреса, то пользователь должен сам заботится о создании/удалении объектов. Как быть? Что посоветуете из опыта?
Re: динамические структуры данных
От: Vamp Россия  
Дата: 27.06.08 23:30
Оценка: 2 (1)
А>Если я создаю некоторую динамическую структуру данных, например бинарное дерево в чистом С, то мне придётся либо реализовать дерево для каждого типа отдельно (int, char, char*, struct {...} и т.д.) либо реализовать дерево для void*. Есть ли другие возможности?
Есть. Можно породить макросы, которые будут порождать типизированные контейнеры. По крайней мере, не будет бесконечных типа небезопассных преобразований.

А>Если просто сохраням адреса, то пользователь должен сам заботится о создании/удалении объектов. Как быть? Что посоветуете из опыта?

Да, пользователь будет хранить указатели, о которых будет заботится сам. Имеет смысл добавить в контейнер всякие функции по его очистки, типа delete_all().
Да здравствует мыло душистое и веревка пушистая.
Re: динамические структуры данных
От: c-smile Канада http://terrainformatica.com
Дата: 28.06.08 00:00
Оценка: 3 (1)
Здравствуйте, Аноним, Вы писали:

А>Если я создаю некоторую динамическую структуру данных, например бинарное дерево в чистом С


Посмотри как например сделано здесь: http://home.gna.org/gdsl/
Re: динамические структуры данных
От: Erop Россия  
Дата: 28.06.08 05:26
Оценка: 4 (2)
Здравствуйте, Аноним, Вы писали:

А>Во втором случае возникает вопрос: если я помещаю в дерево элемент (функция insert_item), каковы мои действия? Например, создаем копи объекта, который хотим иметь в дереве и помещаем её (копию) в него (дерево). Но, как тогда узнать размер объекта? Особенно если это строки? (делать константу МАХ_SIZE?)


Например, если твои данные не предполагают хранения каких-то ещё дополнительных владеющих указателей, то можно сделать как-то так:
typedef struct TreeElementTag {
    TreeElement* parent;
    TreeElement* next;
    TreeElement* prev;
    int size;
} TreeElement;
void* GetTreeElementData( TreeElement* element )
{
    assert( element != 0 );
    return element + 1;
}
TreeElement* CreateTreeElement( void* data, int dataSize )
{
    TreeElemnt tmp = { 0, 0, 0, dataSize );
    TreeElement* res = malloc( sizeof( TreeElemnt ) + dataSize );
    assert( res != 0 && dataSize >= 0 );
    *res = tmp;
    if( dataSize > 0 ) {
        assert( data != 0 );
        memcpy( GetTreeElementData( res ), data, dataSize );
    }
    return res;
}
void DestrpyTreeElement( TreeElement* element ) { free( element ); }
строки можно будет хранить так:
TreeElement* CreateTreeElementByString( char* str )
{
    assert( str != 0 );
    return CreateTreeElement( str, strlen( str ) + 1 );
}
char* GetTreeElementStr( TreeElement* element )
{
    assert( element != 0 );
    return element->size == 0 ? "" : GetTreeElementData( element );
}


В принципе. в такой технике можно хранить довольно развесистые структуры данных даже. Просто они должны уметь упаковываться в единый буфер.

А>Если просто сохраням адреса, то пользователь должен сам заботится о создании/удалении объектов. Как быть? Что посоветуете из опыта?

Ну можно, например, завести такую структуру
typedef struct TypeTreatsTag {
    int obj_sizeof; /* sizeof объекта или <= 0, если размер заранее неизвестен */
    void (*delete_obj)( void* obj, TypeTreatsTag* treats ); /* разрушить объект и освободить занимаемую им памяьть */
    void* (*dynamic_clone)( void* obj, TypeTreatsTag* treats ); /* скопировать объект на кучу */
/*  Тут можно добавить что-то ещё, если надо будет в будующем */
} TypeTreats;

#define SIMPLE_TYPE_TREATS_INITIALYZER( type ) { sizeof( type ), 0, 0 }
void* CloneByTypeTreats_Default( void* obj, TypeTreats* treats );
void* CloneByTypeTreats_Str( void* obj, TypeTreats* treats );

extern TypeTreats TypeTreatsTreats = SIMPLE_TYPE_TREATS_INITIALYZER( TypeTreats ); /* сама структура вроде бы POD */


/* Примеры описания treats */
extern TypeTreats IntTreats = SIMPLE_TYPE_TREATS_INITIALYZER( int );
extern TypeTreats StrTreats = { 0, 0, CloneByTypeTreats_Str };

/* разрушить объект */
void DeleteByTreats( void* obj, TypeTreats* treats )
{
    assert( treats != 0 );
    if( obj == 0 )
        return;
    if( treats != 0 && treats->delete_obj!= 0 ) { 
        treats->delete_obj( obj, treats );
    } else {
        free( obj );
    }
}
/* скопировать объект */
void* CloneByTypeTreats( void* obj, TypeTreats* treats )
{
    assert( treats != 0 );
    if( obj == 0 )
        return 0;
    if( treats != 0 && treats->dynamic_clone != 0 ) { 
        return treats->dynamic_clone( obj, treats );
    } else {
        return CloneByTypeTreats_Default( obj, treats );
    }
}

/* можно химичить с управлением аллокаторами, например так: */
TypeTreats CreateStaticTypeTreats( TypeTreats src )
{
    src.delete_obj = 0;
    return src;
}
/* реализация копии того, что в C++ называют POD */
void* CloneByTypeTreats_Default( void* obj, TypeTreats* treats )
{
    void* res;
    assert( obj != 0 && treats != 0 && treats->obj_sizeof > 0 );
    res = malloc( treats->obj_sizeof );
    assert( res != 0 );
    if( res != 0 )
        memcpy( res, obj, treats->obj_sizeof );
    return res;
}
/* реализация копии строки */
void* CloneByTypeTreats_Str( void* obj, TypeTreats* treats )
{
    char* res;
    int len;
    assert( obj != 0 && treats != 0 && treats->obj_sizeof <= 0 );
    len = strlen( obj );
    res = malloc( len + 1 );
    assert( res == 0 );
    if( res != 0 ) {
        strcpy( res, obj );
    }
    return res;
}
Ну и теперь для всех своих типов описываешь где-то статические TypeTreats, а во всех контейнерах хранишь пару из void* и TypeTreats*. Получишь абсолютный полиморфизм и динамическую типизацию . Особенно, если в струткуру TypeTreats добавить поле void* additional_data. Тогда можно будет динамически порождать сложные иерархии типов
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
pure c полиморфизм
Re: динамические структуры данных
От: sokel Россия  
Дата: 30.06.08 06:22
Оценка: 1 (1)
Здравствуйте, Аноним, Вы писали:

А>Уважаемые эксперты. У меня вопрос по ликбезу.

А>Если я создаю некоторую динамическую структуру данных, например бинарное дерево в чистом С, то мне придётся либо реализовать дерево для каждого типа отдельно (int, char, char*, struct {...} и т.д.) либо реализовать дерево для void*. Есть ли другие возможности?

А>Во втором случае возникает вопрос: если я помещаю в дерево элемент (функция insert_item), каковы мои действия? Например, создаем копи объекта, который хотим иметь в дереве и помещаем её (копию) в него (дерево). Но, как тогда узнать размер объекта? Особенно если это строки? (делать константу МАХ_SIZE?)


А>Если просто сохраням адреса, то пользователь должен сам заботится о создании/удалении объектов. Как быть? Что посоветуете из опыта?


Я бы сделал универсальное дерево — работа с нодами через void* (внешний механизм аллокации, обычно копирование в деревьях излишне), доступ к линкам-цвету по смещению + указатель на функцию для сравнения элементов.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.