venerdì 31 agosto 2007
No OOXML, no piccolo&moscio
E ora la mia critica: supponiamo che io voglia scrivere del software in grado di interagire con documenti salvati in formato ODF: è uno standard aperto e mi garantisce la compatibilità con tutti i sistemi SERI. Perchè mai dovrei scrivere anche il "codec" per la lettura dei documenti ooxml? Ma chi me lo fa fare di spendere il doppio di tempo (soldi)?
Uno standard c'è già, e funziona.
VOTATE LA PETIZIONE CONTRO M$, NON FATEMI LAVORARE IL DOPPIO!
mercoledì 29 agosto 2007
Memory manager errata corrige
Se a qualcuno interessa il codice giusto, mandatemi una mail che ve lo spedisco!
MemoryManager.cpp
namespace ManagedMemory
{
using namespace std;
MemoryManagerImpl::MemoryManagerImpl(void *p, size_t heapSize):
_heapSize(heapSize),
_heap(p)
{
_freeBlocks.push_front(MemBlock(_heap, _heapSize));
}
MemoryManagerImpl::~MemoryManagerImpl(void)
{
}
void * MemoryManagerImpl::alloc(size_t amount) throw(MemoryAllocationException)
{
for(list
{
if(it->_size >= amount)
{
void *memPointer = it->_pointer;
size_t memResidua = it->_size - amount;
_freeBlocks.erase(it);
_usedBlocks.push_back(MemBlock(memPointer, amount));
if(memResidua > 0)
_freeBlocks.push_back(
MemBlock(reinterpret_cast
reinterpret_cast
memResidua));
return memPointer;
}
}
return 0;
}
void MemoryManagerImpl::free(void *p) throw(NotOwnedMemoryException, DeallocOnNotAllocatedMemory)
{
if(
( reinterpret_cast
( reinterpret_cast
) throw NotOwnedMemoryException();
for(list
{
if(it->_pointer == p)
{
_freeBlocks.push_back(*it);
defrag();
_usedBlocks.erase(it);
return;
}
}
throw DeallocOnNotAllocatedMemory();
}
void MemoryManagerImpl::defrag()
{
if(_freeBlocks.size() < 2) return;
_freeBlocks.sort();
list
list
it2++;
while(it2 != _freeBlocks.end())
{
if(
(reinterpret_cast
it1->_size) == (reinterpret_cast
{
// Unisco e libero
_freeBlocks.push_back(MemBlock(it1->_pointer, it1->_size + it2->_size));
_freeBlocks.erase(it2);
_freeBlocks.erase(it1);
// Ricomincio
if(_freeBlocks.size() < 2) return;
_freeBlocks.sort();
it1 = _freeBlocks.begin();
it2 = _freeBlocks.begin();
it2++;
}
else
{
it1++;
it2++;
}
}
}
};
MemoryManager.h
#pragma warning( disable : 4290 )
#include
#include "MemoryExceptions.h"
namespace ManagedMemory
{
struct MemBlock
{
void *_pointer;
size_t _size;
MemBlock(void *pointer, size_t size):
_pointer(pointer), _size(size)
{}
bool operator< (const MemBlock& b) const
{
return
reinterpret_cast
reinterpret_cast
}
};
/**
Interfaccia per gestore di memoria
*/
class MemoryManager
{
public:
virtual void *alloc(size_t amount) throw(MemoryAllocationException) = 0;
virtual void free(void *p) throw(NotOwnedMemoryException) = 0;
};
class MemoryManagerImpl: public MemoryManager
{
void *_heap;
size_t _heapSize;
std::list
std::list
protected:
void defrag();
public:
MemoryManagerImpl(void *p, size_t heapSize);
virtual ~MemoryManagerImpl(void);
virtual void *alloc(size_t amount) throw(MemoryAllocationException);
virtual void free(void *p) throw(NotOwnedMemoryException, DeallocOnNotAllocatedMemory);
};
};
MemoryExceptions.h
namespace ManagedMemory
{
class MemoryException
{};
class MemoryAllocationException: public MemoryException
{};
class NotOwnedMemoryException: public MemoryException
{};
class DeallocOnNotAllocatedMemory: public MemoryException
{};
};
Memory management in C++
lunedì 27 agosto 2007
Pool di risorse e gestione della memoria
Recentemente mi sono messo a meditare sulla gestione della memoria in Java: visto l’alto costo della new
, pensavo di creare un generico contenitore template Pool
in grado di contenere e riutilizzare risorse senza invocare la new
; chiaramente gli oggetti avrebbero dovuto essere “abilitati” al riutilizzo attraverso un metodo di “rigenerazione” che facesse lo stesso lavoro di un’invocazione al distruttore + un’invocazione al costruttore senza coinvolgere il gestore della memoria della virtual machine (in C++ basterebbe sovraccaricare l’operatore di assegnamento). A questo punto avrei voluto implementare un qualche sistema per “sentire” l’uscita dallo scope di una reference all’oggetto per poter indicare al Pool
quando segnare l’oggetto come inutilizzato e renderlo disponibile per essere riutilizzato. Non ci sono riuscito, e mi sono accontentato di un metodo “release” da invocare manualmente, rendendo così l’utilizzo di questo sistema soggetto ai soliti errori di memory leak, e quindi inutile.
Così ho cominciato a ragionare in C++: il meccanismo più efficiente per abbattere i costi dell’allocazione di memoria (in particolare la copia di oggetti complessi) è l’utilizzo di referenze come parametri di funzioni che consentono un comportamento “Java like” (e quindi il polimorfismo…) in modo totalmente trasparente al programmatore (che non deve gestire cioè manualmente la memoria): il limite delle referenze è che funzionano solo in una direzione (verso l’alto dello stack) e quindi non possono essere utilizzate per delle object factory. La soluzione è utilizzare gli auto_ptr, per consentire l’utilizzo di simil-referenze anche verso il basso dello stack: è così possibile creare una funzione del tipo:auto_ptr<resourcehandler> getResource(…);
A questo punto il distruttore di ResourceHandler avrà il compito di “rilasciare” la risorsa dal pool, e questo rilascio avverrà in automatico all’atto dell’uscita dallo scope dell’auto_ptr (bisogna quindi definire come virtuale il distruttore, per poter specializzare liberamente ResourceHandler
).
Rimane però un problema: gli auto_ptr
non possono essere utilizzati nei contenitori stl standard (o forse si… non mi ricordo come funzionano gli allocatori…). Certo che se Java mettesse a disposizione una callback tipo “finalize” (chiamiamola “referenceOutOfScope”) all’uscita dello scope di una referenza, il suo potenziale espressivo crescerebbe molto, mantenendo comunque la semplicità della gestione automatica della memoria.