Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Estensioni C++: i rich pointer

Arricchire i puntatori con informazioni sui tipi introducendo introspezione e riflessione
Arricchire i puntatori con informazioni sui tipi introducendo introspezione e riflessione
Link copiato negli appunti

I rich pointer sono un nuovo costrutto C++, proposto da Dean Michael Berris , che si propone di associare al concetto di puntatore una serie di informazioni sugli oggetti a runtime.

Le novità più importanti introdotte da questo costrutto sono:

  • L'introduzione di introspezione e riflessione runtime, tramite l'utilizzo di opportuni descrittori
  • Compatibilità con i tradizionali puntatori dei quali eredita il comportamento.

In questo articolo ci occuperemo di fornirne una panoramica introduttiva e qualche primo esempio pratico.

Definizione del problema

I puntatori sono uno dei costrutti più importanti del linguaggio C++ ma non si adattano molto bene ad alcuni contesti applicativi dato che non mettono a disposizione strumenti per effettuare le seguenti operazioni:

  • trovare il tipo di un oggetto di cui si conosce la locazione di memoria;
  • visualizzare la struttura di un tipo dinamico runtime;
  • determinare la relazione tra due tipi runtime;
  • creare nuovi tipi di dato runtime, descriverli e ispezionarli.

In generale si tratta di costrutti della programmazione dinamica chiamati introspezione e riflessione runtime. Tipicamente introdurre tali costrutti è costoso e la loro implementazione richiede l'introduzione di una macchina virtuale. Il costrutto rich pointer mira a fornire una soluzione meno onerosa e più flessibile.

Soluzione proposta

Con il rilascio dello standard C++11 sono già state accettate tre tipologie di smart pointer in virtù dei vantaggi che apportano nello sviluppo di codice C++. I nuovi smart pointer, inclusi nella libreria standard, sono unique_ptr, shared_ptr e weak_ptr e incapsulano pattern generici per gestire la memoria in maniera trasparente all'utente.

I rich pointer seguono l'idioma degli smart pointer ma non propongono di tenere traccia solo della locazione di memoria di un dato oggetto ma anche di un descrittore di tipo, ovvero un riferimento ad una rappresentazione immutabile del tipo dell'oggetto.

Nella proposta è prevista anche la compatibilità con i normali puntatori con la limitazione che, nel caso in cui si assegni un rich pointer ad un normale puntatore, viene trasferita solo la locazione di memoria mentre il descrittore del tipo viene rimosso.

La sintassi dei rich pointer

Anche dal punto di vista sintattico i rich pointer si comporterebbero come dei normali puntatori. La sintassi riportata nel paper utilizza il simbolo % (percentuale) per la loro definizione. Supponendo di voler allocare un rich pointer ad una struttura foo così definita:

struct foo {
  foo() {}
  ~ foo() {}
};

sarebbe sufficiente inizializzare il rich pointer nel seguente modo:

foo %p = new(std::rich) foo;

Per accedere al descrittore di tipo memorizzato in un rich-pointer è stata prevista una funzione chiamata type_descriptor che ritorna un puntatore ad un oggetto contenente informazioni sul tipo. I descrittori dei tipi di dato sarebbero generati direttamente dal compilatore e non dovrebbero essere gestiti manualmente dallo sviluppatore.

I descrittori che sono stati previsti sono più di uno, ognuno dei quali fornisce delle informazioni aggiuntive per un tipo specifico: function_descriptor_t, field_descriptor_t, type_descriptor_t e method_descriptor_t.

Ogni descrittore conterrà varie informazioni su tutti i costrutti. Ad esempio la semplice classe foo vista in precedenza genererebbe internamente i seguenti descrittori:

Descrittore per il costruttore:

static function_descriptor_t const foo_ctor_o {
    "::foo::foo", // nome della funzione
    Nullptr, // tipo del risultato
    {}, // nessun argomento
    function_descriptor_t::NORMAL // qualificatori
    function_descriptor_t::CONSTRUCTOR, // type
    null_ptr, // specifica se è membro di un altra classe
    &_destructor<foo>::callable // definizione dell'implementazione
}

Descrittore per il distruttore

static function_descriptor_t const foo_dtor_o {
    "::foo::~ foo", // nome della funzione
    Nullptr, // tipo del risultato
    {}, // nessun argomento
    function_descriptor_t::NORMAL // qualificatori
    function_descriptor_t::DESTRUCTOR, // type
    null_ptr, // specifica se è membro di un altra classe
    &_destructor<foo>::callable // definizione dell'implementazione
}

Descrittore per la struttura

static type_descriptor_t const foo_type {
    "::foo", // nome del tipo
    {nullptr}, // non eredita da nessuno
    {
        { method_descriptor_t::PUBLIC,
          method_descriptor_t_NORMAL,
          &foo_ctor_0
        },
        { method_descriptor_t::PUBLIC,
          method_descriptor_t_NORMAL,
          &foo_dtor_0
        },
        nullptr
    }, // funzioni
    sizeof(foo) // la dimensione determinata staticamente
}

Esempio di rich pointer

Di seguito è riportato un semplice esempio di utilizzo che dichiara un rich pointer, estrae il descrittore e ne stampa a video il nome del tipo.

#include <iostream>
#include <string>
#include <runtime>
int main(int argc, char *argv[])
{
	foo %f = new(std::rich) foo;
	// La seguente istruzione stamperà a video ::foo
	std::cout << type_descriptor(f)->name << std::endl;
	delete f;
	return 0;
}

Un caso d'uso

Per comprendere l'utilità di un costrutto di tal tipo nel paper vengono proposti diversi esempi tra cui una applicazione server che debba assicurare un funzionamento continuo senza interruzioni. Come si potrebbe aggiornare una applicazione di tal tipo?

Il web server Apache, ad esempio, si basa su un protocollo molto stringente che definisce come debbano essere descritti gli oggetti dinamici: tutte le estensioni sono implementate attraverso questo sistema che nel momento in cui viene caricato un nuovo modulo all'interno del sistema in esecuzione, si basa sul linker dinamico per risolvere i simboli seguendo la convenzione adottata.

Con i rich-pointers questo problema potrebbe essere risolto aggiungendo tipi registrati dinamicamente come plugin ad un server che usa i rich pointers. Il caso di studio con tutto il codice correlato è disponibile a pagina 15 del draft N3340.

Conclusioni: Il white paper n3340

Questa overview iniziale ci può essere d'aiuto a leggere ed approfondire tutti i dettagli le caratteristiche e i descrittori dei rich pointer che si trovano all'interno del white paper n3340, il documento ufficiale della proposta del nuovo standard.

Fonti e link utili

Ti consigliamo anche