In einigen Fällen, wie dem beschriebenen, ermöglicht der C ++ - Standard Compilern, Konstrukte auf die Weise zu verarbeiten, die ihre Kunden am nützlichsten finden, ohne dass das Verhalten vorhersehbar sein muss. Mit anderen Worten, solche Konstrukte rufen "undefiniertes Verhalten" auf. Dies bedeutet jedoch nicht, dass solche Konstrukte "verboten" sein sollen, da der C ++ - Standard ausdrücklich auf die Zuständigkeit darüber verzichtet, was wohlgeformte Programme "dürfen". Obwohl mir kein veröffentlichtes Begründungsdokument für den C ++ - Standard bekannt ist, deutet die Tatsache, dass es undefiniertes Verhalten ähnlich wie C89 beschreibt, darauf hin, dass die beabsichtigte Bedeutung ähnlich ist: "Undefiniertes Verhalten gibt dem Implementierer die Lizenz, bestimmte Programmfehler, die schwierig sind, nicht abzufangen diagnostizieren.
Es gibt viele Situationen, in denen die effizienteste Art, etwas zu verarbeiten, darin besteht, die Teile einer Struktur zu schreiben, um die sich Downstream-Code kümmern wird, während diejenigen weggelassen werden, die Downstream-Code nicht interessieren. Die Forderung, dass Programme alle Mitglieder einer Struktur initialisieren, einschließlich derer, um die sich nichts kümmern wird, würde die Effizienz unnötig beeinträchtigen.
Darüber hinaus gibt es einige Situationen, in denen es möglicherweise am effizientesten ist, wenn sich nicht initialisierte Daten nicht deterministisch verhalten. Zum Beispiel gegeben:
struct q { unsigned char dat[256]; } x,y;
void test(unsigned char *arr, int n)
{
q temp;
for (int i=0; i<n; i++)
temp.dat[arr[i]] = i;
x=temp;
y=temp;
}
Wenn sich der nachgelagerte Code nicht um die Werte von Elementen kümmert x.dat
oder y.dat
deren Indizes nicht aufgeführt sind arr
, kann der Code wie folgt optimiert werden:
void test(unsigned char *arr, int n)
{
q temp;
for (int i=0; i<n; i++)
{
int it = arr[i];
x.dat[index] = i;
y.dat[index] = i;
}
}
Diese Verbesserung der Effizienz wäre nicht möglich, wenn Programmierer temp.dat
vor dem Kopieren jedes Element explizit schreiben müssten, einschließlich derjenigen, die sich nicht um die nachgelagerten Elemente kümmern würden.
Andererseits gibt es einige Anwendungen, bei denen es wichtig ist, die Möglichkeit eines Datenverlusts zu vermeiden. In solchen Anwendungen kann es nützlich sein, entweder eine Version des Codes zu haben, die instrumentiert ist, um jeden Versuch abzufangen, nicht initialisierten Speicher zu kopieren, ohne zu berücksichtigen, ob nachgeschalteter Code ihn betrachten würde, oder es könnte nützlich sein, eine Implementierungsgarantie für jeden Speicher zu haben deren Inhalt durchgesickert sein könnte, würde auf Null gesetzt oder auf andere Weise mit nicht vertraulichen Daten überschrieben.
Nach allem, was ich sagen kann, unternimmt der C ++ - Standard keinen Versuch zu sagen, dass eines dieser Verhaltensweisen nützlicher als das andere ist, um eine Mandatierung zu rechtfertigen. Ironischerweise kann dieser Mangel an Spezifikation dazu dienen, die Optimierung zu erleichtern. Wenn Programmierer jedoch keine schwachen Verhaltensgarantien ausnutzen können, werden Optimierungen negiert.