Lavoro per un'azienda che utilizza una DSL personalizzata e il mio compito è di portare la VM in C ++.
Sto cercando di farlo in conformità con lo standard C ++ 11, quindi uso auto
quando appropriato, il nuovo per la sintassi, ecc. Ma sto avendo problemi a cercare di "port" una parte del codice che utilizza puntatori grezzi per i nuovi puntatori intelligenti.
Su questo DSL ogni oggetto è derivato da una classe base chiamata MObject, ad esempio i numeri sono gestiti da questa classe:
class MNumber : public MObject {
...
}
La classe responsabile della gestione della memoria VM ha questo aspetto:
class Mallocator {
...
std::vector<MObject*> memory; //where all objects go...
E per, ad esempio, inserire un nuovo MNumber
in memoria, questa è la funzione che chiami:
MNumber* Mallocator::newMNumber(double a) {
MNumber* number = new MNumber {a};
memory.push_back(number);
INCRMEM(number); //updates memory usage and some other stuff
return number;
}
Le variabili definite dall'utente sono memorizzate su una mappa come questa: std::map<std::string, MObject*>
E i passaggi eseguiti dalla VM per creare una nuova variabile definita dall'utente sono più o meno così:
//storing a value on the VM stack
MNumber* number = allocator->newMNumber(...); //allocate the object
stack.push_back(number); //put a reference to the allocated value on the stack
//retrieving object from the stack and creating the variable
string var_name = codeobj->getVarName(instr.arg); //get the name of the variable from user code
value = stack.back(); // get the pointer to the allocated object from the stack
curr_frame->env->setVar(var_name, value); //associate the name to the object in the current scope
Per me è logico che l'oggetto Mallocator
debba contenere la proprietà di ogni MObject
assegnato e lo stack e la mappa delle variabili dovrebbero contenere un "riferimento" alla memoria allocata, poiché leggono solo i valori. Dopo aver cercato sul Web per alcuni giorni e aver guardato Herb Sutter parlare di "Ritorna alle nozioni di base! Essentials of Modern C ++ Style" ho raccolto alcune idee:
- Sulla
newMNumber
crea ununique_ptr
e utilizza il metodo.get()
per restituire un puntatore raw. Questo non annullerebbe lo scopo dell'uso di puntatori intelligenti? - Sulla
newMNumber
restituisciunique_ptr<MNumber>&
e adatta le variabili stack e mappa per lavorare conunique_ptr<MObject>&
- Utilizza
shared_ptr
. Non penso cheshared_ptr
sia la soluzione perché la proprietà non è condivisa - Lascia stare così com'è e gestisci il ciclo di vita dei puntatori da solo (lo sto già facendo comunque)
Quindi le mie domande sono: qual è il modo giusto per affrontare questo problema? Il mio disegno è corretto? Quali altre opzioni ho?
PS1: Mallocator
è un singleton ed è il solo responsabile dell'allocazione degli oggetti e dell'eliminazione degli oggetti dalla memoria il resto della VM funziona solo con i puntatori restituiti da Mallocator
.
PS2: il linguaggio ha più oggetti rispetto ai numeri ma poiché non posso condividere l'intero codice ho usato MNumber come esempio.
PS3: alcuni oggetti, come stringhe e interi, sono memorizzati nella cache così, per esempio, la funzione (non mostrata qui) newMNumber(int a)
consente solo a un oggetto per intero di esistere.
Grazie.