Ich habe Schwierigkeiten, einen gemeinsamen Speicherpuffer zu implementieren, ohne die strengen Aliasregeln von C99 zu durchbrechen.
Angenommen, ich habe einen Code, der einige Daten verarbeitet und einige Arbeitsspeicher benötigt. Ich konnte es so etwas schreiben wie:
Shared Memory-Puffer in C++ ohne gegen strenge Aliasing-Regeln zu verstoßen
void foo(... some arguments here ...) {
int* scratchMem = new int[1000]; // Allocate.
// Do stuff...
delete[] scratchMem; // Free.
}
Dann habe ich eine andere Funktion, die einige andere Sachen tut, die auch einen Kratzer Puffer benötigt:
void bar(...arguments...) {
float* scratchMem = new float[1000]; // Allocate.
// Do other stuff...
delete[] scratchMem; // Free.
}
Das Problem ist, dass foo() und bar () kann während des Betriebs viele Male aufgerufen werden, und die Zuteilung von Heapspeicherplätzen kann in Bezug auf Leistung und Speicherfragmentierung ziemlich schlecht sein. Eine offensichtliche Lösung wäre, einen gemeinsamen, gemeinsam genutzten Speicherpuffer geeigneter Größe einmal zuzuteilen und dann gehen in foo() und bar() als Argument, BYOB-style:
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!
// ...
}
I ich denke, habe jetzt zwei Fragen:
- Wie kann ich einen gemeinsamen gemeinsamen Arbeitsspeicherpuffer implementieren, der nicht gegen Aliasregeln verstößt?
- Obwohl der obige Code gegen strenge Aliasing-Regeln verstößt, wird mit dem Alias kein Schaden angerichtet. Könnte also jeder vernünftige Compiler (optimierten) Code erzeugen, der mich immer noch in Schwierigkeiten bringt?
Dank
"immer gültig, um ein Objekt als eine Folge von Bytes zu interpretieren" ... nur für einige Operationen. Beispielsweise gilt die Operation "Objekt eines beliebigen Typs innerhalb erstellen", die für Bytefolgen gilt, nicht für "ein anderes Objekt, das als Bytefolge interpretiert wird". –
@BenVoigt: Nur in dem Umfang, in dem UB den Speicher eines nicht-trivialen Objekts für etwas anderes verwendet, bevor er den Destruktor aufruft ... Ich denke, an der Anweisung liegt nichts an sich falsch. –
Wenn Sie einen 'float's-Speicher verwenden, um einen' int 'innerhalb zu erstellen, öffnen Sie die Tür für strenge Aliasing-Verletzungen. Tatsächlich glaube ich, dass der Compiler sogar ein Schreiben in den "float" verzögern darf, bis der Speicher für ein "int" wiederverwendet wird (wodurch der Wert von "int" korrumpiert wird), da der Compiler vom strikten Aliasing ausgehen kann Objekte unterschiedlicher Art überlappen sich nicht. Da sich diese Frage speziell mit strengen Aliasing-Regeln beschäftigt, halte ich das für wichtig. Am besten ist es, Speicher zu verwenden, der als 'char []' gestartet wurde. –