Сериализация объектов кусками
От: sch  
Дата: 19.10.05 13:02
Оценка: +1
Ну, раз уж такое дело пошло и нас учат корректно запрещать создавать объекты в стеке, я тоже свои пять копеек оставлю.

Итак, есть класс A:
[c++]
struct A: virtual some_base_class, some_other_class {
virtual f();
};
[/c++]

При записи берем и пишем объект этого класса целиком в поток:
[c++]
A *a = new A();
...
stream.write((const char *) a, sizeof(A));
[/c++]

Теперь, внимание, самое интересное.
Теперь мы читаем класс из потока, пусть нам извсетно что этот класс -- A. Сначала мы заводим буффер, считываем туда блок памяти, а потом конструируем класс в этом буфере с помощью placement new.

[c++]
char *buf = malloc(sizeof(A));
stream.read(buf, sizeof(A));
new (buf) A();
[/c++]

В результате мы получаем все pod-данные A загруженными, да и структура A тоже восстановлена! По-моему здорово.

Дальше надеюсь додумаете сами.

P.S. Маленькая подсказка: если конструктор класса перезаписывает эти самые pod-члены, то можно определить еще один, пустой:

[c++]
struct some_strange_object {};

struct A {
int var;

A() {
var = 0;
}

A(some_strange_object *p) {
}
};

...

char *buf = malloc(sizeof(A));
stream.read(buf, sizeof(A));
new (buf) A((some_strange_object *) 0);
[/c++]

P.P.S. Ну, а не-POD типы нужно будет грузить вручную, пользуясь другими методиками.
Re: Сериализация объектов кусками
От: Pavel Chikulaev Россия  
Дата: 19.10.05 13:07
Оценка: +1
Здравствуйте, sch, Вы писали:


sch>Ну, раз уж такое дело пошло и нас учат корректно запрещать создавать объекты в стеке, я тоже свои пять копеек оставлю.


sch>Теперь, внимание, самое интересное.

sch>Теперь мы читаем класс из потока, пусть нам извсетно что этот класс -- A. Сначала мы заводим буффер, считываем туда блок памяти, а потом конструируем класс в этом буфере с помощью placement new.

sch>[c++]

sch>char *buf = malloc(sizeof(A));
sch>stream.read(buf, sizeof(A));
sch>new (buf) A();
sch>[/c++]

sch>В результате мы получаем все pod-данные A загруженными, да и структура A тоже восстановлена! По-моему здорово.


sch>[c++]

sch>struct some_strange_object {};

sch>struct A {

sch> int var;

sch> A() {

sch> var = 0;
sch> }

sch> A(some_strange_object *p) {

sch> }
sch>};


sch>P.P.S. Ну, а не-POD типы нужно будет грузить вручную, пользуясь другими методиками.


Чем это лучше std::copy или memcpy? Еще одиним бесполезным конструктором?

Сорри конечно, но по-моему это sux
Re[2]: Сериализация объектов кусками
От: sch  
Дата: 19.10.05 13:18
Оценка:
Здравствуйте, Pavel Chikulaev, Вы писали:

sch>>P.P.S. Ну, а не-POD типы нужно будет грузить вручную, пользуясь другими методиками.

Здесь конечно же имелись в виду не-POD члены классов.

PC>Чем это лучше std::copy или memcpy? Еще одиним бесполезным конструктором?

У нас например много классов с большим количеством этих самых POD-членов. Используя эту методику мы значительно уменьшили количество элементов в таблице сериализации. Недостаток основной заключается в том, что очень трудно найти неинициализированный указатель после десериализации.
Re: Сериализация объектов кусками
От: tiam Россия  
Дата: 19.10.05 13:56
Оценка:
Здравствуйте, sch, Вы писали:


sch>Ну, раз уж такое дело пошло и нас учат корректно запрещать создавать объекты в стеке, я тоже свои пять копеек оставлю.


sch>Итак, есть класс A:

sch>[c++]
sch>struct A: virtual some_base_class, some_other_class {
sch> virtual f();
sch>};
sch>[/c++]
[c++][/c++] — это что новые коды форматирования С++?
Так не устраивает:

struct A: virtual some_base_class, some_other_class {
virtual f();
}
Re[2]: Сериализация объектов кусками
От: _Winnie Россия C++.freerun
Дата: 19.10.05 15:46
Оценка:
Здравствуйте, Pavel Chikulaev, Вы писали:

sch>>P.P.S. Ну, а не-POD типы нужно будет грузить вручную, пользуясь другими методиками.


PC>Чем это лучше std::copy или memcpy? Еще одиним бесполезным конструктором?

memcpy перезапишет полезные члены данных.
А нам нужно только записать указатель на таблицу виртуальных фукнций и таблицу смещений виртуальных баз.

PC>Сорри конечно, но по-моему это sux

Это стандартная и общеизвестная методика загрузки данных на игровых консолях, на которых очень мало оперативной памяти и жёсткие требования ко времени загрузки игры.
Там не скажешь, "ну укажем в системных требованиях на 512 мб. оперативной памяти больше."

Целый уровень может быть загружен одним куском памяти.
Правильно работающая программа — просто частный случай Undefined Behavior
Re: Сериализация объектов кусками
От: _Winnie Россия C++.freerun
Дата: 19.10.05 15:53
Оценка:
Здравствуйте, sch, Вы писали:

sch>P.P.S. Ну, а не-POD типы нужно будет грузить вручную, пользуясь другими методиками.




//Author: _Winnie.
//offset_ptr_t<T>, wich can be stored in files and moved along memory

template <class T>
struct offset_ptr_t
{
private:
    size_t m_offset;
    
public:
    /// default constructor do not touch underlying memory. 
    offset_ptr_t()
    {
    }

    //non-explicit constructor. offset_ptr_t does not hold 
    //ownership, so it's ok.
    offset_ptr_t(T *in_p)
    {
        *this = in_p;
    }

    offset_ptr_t &operator=(T *in_p)
    {
        if (in_p)
            m_offset = (size_t)in_p - (size_t)this; 
        else
            m_offset = 0;
        return *this;
    }

    T *operator->() const
    {
        assert(m_offset != 0);        
        return (T*)((size_t)this + m_offset);
    }
    
    T &operator*() const
    {
        return *this->operator->();
    }
    
    T &operator[](size_t in_index) const
    {
        return this->operator->()[in_index];
    }
    
#ifdef NDEBUG
    //avoid "forcing value to bool 'true' or 'false' (performance warning)" MSVC  warning
    operator int()
    {
        return m_offset;
    }
#else
    operator safe_bool_t()
    {
        return m_offset ? safe_true : safe_false;
    }
#endif    
    
    //quick and dirty.
    //operator T*() const
    //{
    //    return operator->();
    //}
    
    offset_ptr_t(const offset_ptr_t &other)
    {
        *this = other;
    }
    
    offset_ptr_t &operator=(const offset_ptr_t &other)
    {
        if (other.m_offset)
        {
            m_offset = (size_t)&other + other.m_offset - (size_t)this;
        }
        else
            m_offset = 0;
        return *this;
    }
    
    T *get() const
    {
        if (m_offset)
            return this->operator->();
        else
            return NULL;
    }
    
    T *get_non_null() const
    {
        return this->operator->();
    }

    ~offset_ptr_t()
    {
        typedef char same_size_static_assert 
        [
          sizeof(m_offset) == sizeof(T*) &&
          sizeof(m_offset) == sizeof(*this)
        ]; //TODO: use BOOST_STATIC_ASSERT instead hand-made bicycle
    }
    
    template <class U> friend bool operator==(const offset_ptr_t<U> &l, const offset_ptr_t<U> &r);
    template <class U> friend bool operator!=(const offset_ptr_t<U> &l, const offset_ptr_t<U> &r);
};

template <class T>
inline bool operator==(const offset_ptr_t<T> &l, const offset_ptr_t<T> &r)
{
    return l.get() == r.get();
}

template <class T>
inline bool operator!=(const offset_ptr_t<T> &l, const offset_ptr_t<T> &r)
{
    return !(l == r);
}
Правильно работающая программа — просто частный случай Undefined Behavior
Re: Сериализация объектов кусками
От: srggal Украина  
Дата: 19.10.05 16:03
Оценка:
Здравствуйте, sch, Вы писали:

Вопросы выравнивания, и платформенных архитектур автором, как я понял оставленны в стороне, Биг/Литле Эндианы — просто отдыхают

Все элегантно, и просто
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[2]: Сериализация объектов кусками
От: srggal Украина  
Дата: 19.10.05 16:04
Оценка:
Здравствуйте, srggal, Вы писали:

S>Здравствуйте, sch, Вы писали:


S>Вопросы выравнивания, и платформенных архитектур автором, как я понял оставленны в стороне, Биг/Литле Эндианы — просто отдыхают


S>Все элегантно, и просто


А может в этом и есьт сермяжная правда
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[2]: Сериализация объектов кусками
От: ruslan_abdikeev Россия http://aruslan.nm.ru
Дата: 19.10.05 16:58
Оценка:
Здравствуйте, _Winnie, Вы писали:

template <class T>
struct offset_ptr_t
{
private:
    size_t m_offset;
public:
    offset_ptr_t &operator=(T *in_p)
    {
        if (in_p)
            m_offset = (size_t)in_p - (size_t)this; 
        else
            m_offset = 0;
        return *this;
    }


У себя я использовал ptrdiff_t.
Код, очевидно, непереносимый ни в том, ни в другом случае.
Но ptrdiff_t явным образом знаковый, плюс не нужно преобразование типа (size_t)in_p.

В общем, работает или не работает и то и другое, но ИМХО ptrdiff_t здесь чище и нагляднее.
Re[3]: Сериализация объектов кусками
От: Erop Россия  
Дата: 19.10.05 22:33
Оценка:
Здравствуйте, _Winnie, Вы писали:

_W>Целый уровень может быть загружен одним куском памяти.


А зачем ему быть таким сложным? Может просто POD сделать да и всё?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.