2017-04-11 3 views
2

on me donne un cadre de C++ (que je ne peux pas changer) pour les opérations d'entrées-sorties qui fonctionne comme ceci:Comment faire classe C++ ont une taille spécifique en mémoire

  • Il a block_size qui est la taille du bloc qui est lu ou écrit
  • Chaque opération de lecture/écriture obtient cette struct opération:
struct Operation { 
    size_t block; // index of external memory block 
    void * data; // here the data will be written or read from 
} 

La lecture réelle ou écriture ressemble à ceci:

Operation o; 
o.block = 42; // index of block i want to read from 
o.data = // where i want the data to end up 
io.read(o); 

Le problème est que la lecture/écriture est mis en œuvre avec memcpy et il se déplace toujours bloc de block_size octets. Cependant, quand je veux enregistrer et charger ma classe X à cette mémoire externe, j'ai un problème, car probablement sizeof(X) != block_size.

Alors, quand je ferais ceci:

X x; 
Operation o; 
o.block = 42; // index of block i want to read from 
o.data = &x; 
io.read(o); 

io.write(o); 

Si je sizeof(X) < block_size un problème au cours de la lecture, parce que plus d'octets que je veux seront lus, peut-être la pile corrompt. Si sizeof(X) > block_size J'ai un problème pendant l'écriture, car tous les octets de X ne seront pas écrits, donc j'ai une sauvegarde incomplète. Je veux utiliser chaque bloc pour une instance de X et je peux m'assurer que sizeof(X) < block_size. Y at-il un moyen d'ajouter des octets de remplissage à X, de sorte qu'il a exactement block_size octets?

+0

Est-ce que 'block_size' est une constante connue au moment de la compilation? –

+0

Un allocateur d'objet qui ajoute du remplissage en interne peut aider. – felix

+0

@FabioTurati yes la taille de bloc est une constante de temps de compilation. – Jeysym

Répondre

2
X x; 
Operation o; 
o.block = 42; // index of block i want to read from 
o.data = &x; 
io.read(o); 

Eh bien, vous ne pouvez pas faire cela, comme vous l'avez dit. Vous devez pointer vers un bloc block_size, puis copiez dans la classe concernée:

BYTE buffer[block_size]; 
X x; 
Operation o; 
o.block = 42; // index of block i want to write to 
o.data = buffer; 
io.read(o); 
memcpy(&x, buffer, sizeof(X)); 

Même chose pour les écritures (vous ne pouvez pas écrire simplement ce qui arrive à être après la fin de X parce que vous pouvez tomber de la falaise dans une page non mappée):

BYTE buffer[block_size]; 
X x; 
Operation o; 
o.block = 42; // index of block i want to read from 
o.data = buffer; 
memcpy(buffer, &x, sizeof(X)); 
io.write(o); 

Je ne commenterai pas la santé mentale de l'interface elle-même. Et static_assert(sizeof(X) <= block_size). Et le type X doit être sécurisé pour la memcopie.

Il y a plus de trucs dans le livre, comme faire sizeof(X) toujours correspondre block_size (via padding) ou utiliser des astuces d'allocation (toujours allouer X dans les régions block_size, ne jamais utiliser sur la pile). Mais copier avant d'écrire/après la lecture est le plus simple, le moins délicat.