Sto lottando con l'implementazione di un buffer di memoria condiviso senza interrompere le rigide regole di aliasing di C99.
Supponiamo di avere un codice che elabora alcuni dati e che deve avere una memoria "scratch" per funzionare. Potrei scrivere come qualcosa di simile a:
Buffer di memoria condivisa in C++ senza violare le rigide regole di aliasing
void foo(... some arguments here ...) {
int* scratchMem = new int[1000]; // Allocate.
// Do stuff...
delete[] scratchMem; // Free.
}
Poi ho un altro funzione che fa un po 'di altre cose che ha anche bisogno di un buffer di zero:
void bar(...arguments...) {
float* scratchMem = new float[1000]; // Allocate.
// Do other stuff...
delete[] scratchMem; // Free.
}
Il problema è che foo() e bar () può essere chiamato più volte durante l'operazione e avere allocazioni di heap in tutto il luogo può essere piuttosto negativo in termini di prestazioni e frammentazione della memoria. Una soluzione ovvia sarebbe quella di allocare un buffer di memoria comune condivisa di dimensioni appropriate una volta e poi passare in foo() e bar() come argomento, BYOB stile:
void foo(void* scratchMem);
void bar(void* scratchMem);
int main() {
const int iAmBigEnough = 5000;
int* scratchMem = new int[iAmBigEnough];
foo(scratchMem);
bar(scratchMem);
delete[] scratchMem;
return 0;
}
void foo(void* scratchMem) {
int* smem = (int*)scratchMem;
// Dereferencing smem will break strict-aliasing rules!
// ...
}
void bar(void* scratchMem) {
float* smem = (float*)scratchMem;
// Dereferencing smem will break strict-aliasing rules!
// ...
}
immagino I avere due domande ora:
- Come posso implementare un buffer di memoria scratch comune condiviso che non violi le regole di aliasing?
- Anche se il codice precedente viola le rigide regole di aliasing, non viene eseguito alcun "danno" con l'alias. Quindi un qualsiasi compilatore sano può generare codice (ottimizzato) che mi mette ancora nei guai?
Grazie
"sempre valido per interpretare un oggetto come una sequenza di byte" ... solo per alcune operazioni. Ad esempio, l'operazione "Crea un oggetto di qualsiasi tipo all'interno" che si applica alle sequenze di byte non si applica a "un altro oggetto interpretato come una sequenza di byte". –
@BenVoigt: Solo nella misura in cui è UB utilizzare l'archiviazione di un oggetto non banale per qualcos'altro prima di chiamare il distruttore ... Penso che non ci sia nulla di intrinsecamente sbagliato nell'istruzione. –
Se si utilizza una memoria 'float' per creare un' int' all'interno, si apre la porta a violazioni rigorose di aliasing. In effetti, penso che il compilatore possa anche essere autorizzato a posticipare una scrittura al 'float' fino a dopo che la memoria viene riutilizzata per un' int' (corrompendo il valore di 'int'), perché l'aliasing rigoroso consente al compilatore di assumere che gli oggetti di diverso tipo non si sovrappongano. Poiché questa domanda riguarda in particolare le rigide regole di aliasing, ritengo che sia importante. La cosa migliore è usare la memoria iniziata come 'char []'. –