Давать или не давать?
От: Ухты  
Дата: 11.06.09 22:51
Оценка: :)
Всем привет. Мучаюсь исключительно женским вопросом
Есть такой класс

template<bla-bla>
class MemChunk
{
    void *mem;
    unsigned int nWrittenBytes;
...
    unsigned int write(const void *data, unsigned int dataSize);
}


Иногда возникает необходимость отдать mem наружу — например, его может домагиваться fread(). Задача — сохранить состояние валидным(т.е nWrittenBytes поправить в нужном количестве).
Какие вижу варианты:
1. Ничего никому не давать. Ибо нефиг. Минусы — оверхед на дополнительном выделении памяти под буфер и его копирование внутрь.
2. Давать, и молиться, чтобы не забыли также потом позвать setDataSize(или adjust, не суть).
3. Давать, но чтоб женился — через функтор(функцию?), который вернёт использованный размер. Многих пугает организация подобных мероприятий.
4. Подсказка из зала.
Re: Давать или не давать?
От: Аноним  
Дата: 12.06.09 00:50
Оценка:
Здравствуйте, Ухты, Вы писали:

У>Всем привет. Мучаюсь исключительно женским вопросом

В таком случае ответы наверняка будут мужскими =)

У>Есть такой класс


У>
У>template<bla-bla>
У>class MemChunk
У>{
У>    void *mem;
У>    unsigned int nWrittenBytes;
У>...
У>    unsigned int write(const void *data, unsigned int dataSize);
У>}

У>


У>Иногда возникает необходимость отдать mem наружу — например, его может домагиваться fread(). Задача — сохранить состояние валидным(т.е nWrittenBytes поправить в нужном количестве).

...
У>3. Давать, но чтоб женился — через функтор(функцию?), который вернёт использованный размер. Многих пугает организация подобных мероприятий.

Вот этот вариант мне импонирует больше всех. + такая функция(м.б. интерфейс(*) должна сама заботится о выполнении инвариантов. Т.е. если что-то нужно подправить, то она и должна это выполнять.

(*) Интерфейс "вообще" (не обязательно с виртуальными функциями)
Re: Давать или не давать?
От: Кодт Россия  
Дата: 15.06.09 10:02
Оценка: 1 (1)
Здравствуйте, Ухты, Вы писали:

У>1. Ничего никому не давать. Ибо нефиг. Минусы — оверхед на дополнительном выделении памяти под буфер и его копирование внутрь.

У>2. Давать, и молиться, чтобы не забыли также потом позвать setDataSize(или adjust, не суть).
У>3. Давать, но чтоб женился — через функтор(функцию?), который вернёт использованный размер. Многих пугает организация подобных мероприятий.
У>4. Подсказка из зала.

Сделать пару методов get_buffer(size1) / release_buffer(size2), size2 <= size1
И уже поверх этих примитивов делать scope guard, который финализировал бы резервирование буфера.
template<blablabla>
class mem_chunk
{
    .....
    void* get_buffer(size_t required);
    void release_buffer(size_t written);
    void release_whole_buffer(); // written = required
};

struct nodelete
{
    void operator()(void*) {}
};

template<blablabla>
class mem_chunk_buffer_t
{
    typeef mem_chunk<blablabla> the_chunk;
    
    unique_ptr<the_chunk, nodelete> host; // эстафетное упоминание (чтобы промежуточные объекты не пытались финализировать повторно)
    
    mem_chunk_buffer_t(the_chunk* host, size_t required) : host(host) { host->get_buffer(required); }
    ~mem_chunk_buffer_t() { if(host) host->release_whole_buffer(); }
};

template<blablabla>
mem_chunk_buffer_t<blablabla>
mem_chunk_buffer(mem_chunk<blablabla>& chunk, size_t size)
{
    return mem_chunk_buffer_t<blablabla>(&chunk, size);
}


......
mem_chunk<xxxxx> mc;
fread(mem_chunk_buffer(mc, 123), 1, 123, fp);
assert(mc.nWrittenBytes == 123);


(Навеяно ATL CStringT + CStrBufT)

Можно, конечно, поизвращаться — чтобы scope guard предоставлял пару (void*,size_t*). Клиентский код неким способом прочитает указатель на буфер, что-то там с ним сделает и запишет размер "куда следует". А затем scope guard выполнит release_buffer с этим размером.
Но переделывать клиентский код придётся основательно.

Так что проще уж перегрузить fread для работы с mem_chunk, чтоб оно само финализировало как полагается.
void fread(mem_chunk& mc, size_t elem, size_t count, FILE* fp)
{
    size_t done = fread(mc.get_buffer(count*elem), elem, count, fp);
    mc.release_buffer(done*elem);
}

(Ну или не перегрузить, а переименовать — тут уже на вкус и цвет).
... << RSDN@Home 1.2.0 alpha 4 rev. 1207>>
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.