Quels sont tous les comportements communs non définis qu'un programmeur C ++ devrait connaître?
Dire, comme:
a[i] = i++;
Quels sont tous les comportements communs non définis qu'un programmeur C ++ devrait connaître?
Dire, comme:
a[i] = i++;
NULL
pointeurmemcpy
pour copier le chevauchement des tampons.int64_t i = 1; i <<= 72
n'est pas défini)int i; i++; cout << i;
)volatile
ou sig_atomic_t
à la réception d'un signallong int
#if
expressionL'ordre que les paramètres de la fonction sont évalués est quelconque comportement. (Cela ne fera pas votre plantage du programme, exploser, ou commander une pizza... à la différence de undefined comportement.)
La seule exigence est que tous les paramètres doivent être évaluées avant que la fonction est appelée.
Ce:
// The simple obvious one.
callFunc(getA(),getB());
Peut être équivalent à ceci:
int a = getA();
int b = getB();
callFunc(a,b);
Ou ceci:
int b = getB();
int a = getA();
callFunc(a,b);
Il peut être soit; c'est le compilateur. Le résultat peut, selon les effets secondaires.
Le compilateur est libre de réorganiser les parties d'évaluation d'une expression (en supposant que la signification est inchangée).
De la question originale:
a[i] = i++;
// This expression has three parts:
(a) a[i]
(b) i++
(c) Assign (b) to (a)
// (c) is guaranteed to happen after (a) and (b)
// But (a) and (b) can be done in either order.
// See n2521 Section 5.17
// (b) increments i but returns the original value.
// See n2521 Section 5.2.6
// Thus this expression can be written as:
int rhs = i++;
int lhs& = a[i];
lhs = rhs;
// or
int lhs& = a[i];
int rhs = i++;
lhs = rhs;
Double verrouillage à carreaux. Et une erreur facile à faire.
A* a = new A("plop");
// Looks simple enough.
// But this can be split into three parts.
(a) allocate Memory
(b) Call constructor
(c) Assign value to 'a'
// No problem here:
// The compiler is allowed to do this:
(a) allocate Memory
(c) Assign value to 'a'
(b) Call constructor.
// This is because the whole thing is between two sequence points.
// So what is the big deal.
// Simple Double checked lock. (I know there are many other problems with this).
if (a == null) // (Point B)
{
Lock lock(mutex);
if (a == null)
{
a = new A("Plop"); // (Point A).
}
}
a->doStuff();
// Think of this situation.
// Thread 1: Reaches point A. Executes (a)(c)
// Thread 1: Is about to do (b) and gets unscheduled.
// Thread 2: Reaches point B. It can now skip the if block
// Remember (c) has been done thus 'a' is not NULL.
// But the memory has not been initialized.
// Thread 2 now executes doStuff() on an uninitialized variable.
// The solution to this problem is to move the assignment of 'a'
// To the other side of the sequence point.
if (a == null) // (Point B)
{
Lock lock(mutex);
if (a == null)
{
A* tmp = new A("Plop"); // (Point A).
a = tmp;
}
}
a->doStuff();
// Of course there are still other problems because of C++ support for
// threads. But hopefully these are addresses in the next standard.
En plus d' un comportement indéterminé, il est également tout aussi méchant de mise en œuvre définies par le comportement.
Comportement indéfini se produit lorsqu'un programme fait quelque chose dont le résultat n'est pas spécifiée par la norme.
La mise en œuvre définies par le comportement est une action par un programme dont le résultat n'est pas défini par la norme, mais dont la mise en œuvre du document. Un exemple est le "multi-octets de caractères littéraux", de Dépassement de Pile question Est-il un compilateur C qui ne parvient pas à le compiler?.
Mise en œuvre-comportement défini uniquement les morsures de vous lorsque vous commencez à portage (mais la mise à niveau vers la nouvelle version de compilateur est aussi le portage!)
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.