L'optimisation de la base vide est excellente. Cependant, il est livré avec la restriction suivante:
L'optimisation de base vide est interdite si l'une des classes de base vide est également le type ou la base du type du premier membre de données non statique, car les deux sous-objets de base du même type doivent avoir des adresses différentes dans la représentation d'objet du type le plus dérivé.
Pour expliquer cette restriction, considérez le code suivant. Le static_assert
échouera. Alors que la modification de Foo
ou Bar
de hériter à la place Base2
évitera l'erreur:
#include <cstddef>
struct Base {};
struct Base2 {};
struct Foo : Base {};
struct Bar : Base {
Foo foo;
};
static_assert(offsetof(Bar,foo)==0,"Error!");
Je comprends parfaitement ce comportement. Ce que je ne comprends pas, c'est pourquoi ce comportement particulier existe . Il a évidemment été ajouté pour une raison, car il s'agit d'un ajout explicite et non d'un oubli. Quelle en est la raison?
En particulier, pourquoi les deux sous-objets de base devraient-ils avoir des adresses différentes? Dans ce qui précède, Bar
est un type et foo
est une variable membre de ce type. Je ne vois pas pourquoi la classe de base Bar
importe pour la classe de base du type de foo
, ou vice-versa.
En effet, je ne sais quoi, je m'attendrais à ce que ce &foo
soit la même que l'adresse de l' Bar
instance qui la contient - comme cela doit être dans d'autres situations (1) . Après tout, je ne fais rien d'extraordinaire avec l' virtual
héritage, les classes de base sont vides malgré tout, et la compilation avec Base2
montre que rien ne casse dans ce cas particulier.
Mais il est clair que ce raisonnement est incorrect d'une manière ou d'une autre, et il existe d'autres situations où cette limitation serait requise.
Disons que les réponses devraient être pour C ++ 11 ou plus récent (j'utilise actuellement C ++ 17).
(1) Remarque: EBO a été mis à niveau en C ++ 11, et en particulier est devenu obligatoire pour StandardLayoutType
s (bien que Bar
, ci-dessus, ce ne soit pas a StandardLayoutType
).
Base *a = new Bar(); Base *b = a->foo;
aveca==b
, maisa
et ceb
sont clairement des objets différents (peut-être avec des remplacements de méthode virtuelle différents).