Cette FAQ concerne les agrégats et les POD et couvre les éléments suivants:
- Que sont les agrégats ?
- Que sont les POD (Plain Old Data)?
- Comment sont-ils liés?
- Comment et pourquoi sont-ils spéciaux?
- Quels changements pour C ++11?
Cette FAQ concerne les agrégats et les POD et couvre les éléments suivants:
La définition standard d'un ensemble a légèrement changé, mais c'est toujours à peu près la même:
Un agrégat est un tableau ou une classe (Clause 9) sans que l'utilisateur fourni par les constructeurs (12.1), pas de corset ou égal initialiseurs pour les non-membres de données statiques (9.2), no private ou protected non-membres de données statiques (Clause 11), pas de classes de base (article 10), et pas de fonctions virtuelles (10.3).
Ok, ce qui a changé?
Auparavant, un agrégat peut ne pas avoir de l'utilisateur déclaré constructeurs, mais maintenant il ne peut pas avoir de l'utilisateur fourni par les constructeurs. Est-il une différence? Oui, il est, parce que maintenant vous pouvez déclarer les constructeurs et par défaut :
struct Aggregate {
Aggregate() = default; // asks the compiler to generate the default implementation
};
C'est toujours un agrégat parce qu'un constructeur (ou tout membre de la fonction) qui est par défaut sur la première déclaration n'est pas fourni par l'utilisateur.
Maintenant, un total ne peut pas avoir un corset ou égal initialiseurs pour les non-membres de données statiques. Qu'est-ce que cela signifie? Eh bien, c'est simplement parce que cette nouvelle norme, nous pouvons initialiser directement les membres de la classe comme ceci:
struct NotAggregate {
int x = 5; // valid in C++11
std::vector<int> s{1,2,3}; // also valid
};
L'utilisation de cette fonctionnalité rend la classe plus un agrégat parce que c'est essentiellement équivalente à la fourniture de votre propre constructeur par défaut.
Donc, ce qui est un agrégat n'a pas changé grand-chose. C'est toujours la même idée de base, adaptés aux nouvelles fonctionnalités.
Les gousses ont eu beaucoup de changements. Beaucoup de règles précédentes sur les Gousses ont été assouplies dans cette nouvelle norme, et la façon dont la définition est donnée dans la norme a été radicalement modifiée.
L'idée d'une GOUSSE de capture essentiellement deux propriétés distinctes:
De ce fait, la définition a été divisé en deux concepts distincts: le trivial classes et standard-layout classes, car elles sont plus utiles que les POD. La norme utilise rarement le terme POD, préférant le plus spécifique trivial et standard-layout concepts.
La nouvelle définition de dit en gros qu'un POD est une classe qui est à la fois trivial et a standard-layout, et cette propriété doit tenir de manière récursive pour tous les non-membres de données statiques:
Un module struct est une non-union de la classe qui est à la fois un trivial de classe et un standard-classe de mise en page, et n'a pas non données membres statiques de type non-POD struct, non-POD de l'union (ou d'une matrice de ce type). De même, un POD de l'union est une union qui est à la fois un trivial de classe et une mise en page standard de la classe, et a pas de non-données membres statiques de type non-POD struct, non-POD de l'union (ou d'une matrice de ce type). Un module de classe est une classe qui est soit un module struct ou un POD de l'union.
Reprenons chacun de ces deux propriétés en détail séparément.
Trivial est la première propriété mentionnée ci-dessus: trivial classes de soutien initialisation statique.
Si une classe est trivialement copiable (un sur-ensemble de trivial classes), il est ok pour copier sa représentation sur la place avec des choses comme l' memcpy
et espérer que le résultat soit le même.
La norme définit un trivial classe comme suit:
Un trivialement copiable classe est une classe qui:
- n'a pas de non-trivial copie de constructeurs (12.8),
- n'a pas non triviale des constructeurs de déplacement (12.8),
- n'a pas de non-trivial copie des opérateurs d'affectation (13.5.3, 12.8),
- n'a pas non trivial de déplacer des opérateurs d'affectation (13.5.3, 12.8), et
- a un trivial destructeur (12.4).
Un trivial classe est une classe qui a un trivial constructeur par défaut (12.1) et est trivialement copiable.
[ Note: En particulier, un trivialement copiable ou trivial de classe n'ont pas de fonctions virtuelles ou virtuel classes de base.-la note de fin ]
Donc, ce sont tous ceux trivial et non-triviales?
Un copier/déplacer constructeur de la classe X est trivial si il n'est pas fourni par l'utilisateur et si
- la classe X n'a pas de fonctions virtuelles (10.3) et pas de virtuel classes de base (10.1), et
- le constructeur sélectionné pour copier/déplacer chaque classe de base directe sous-objet est trivial, et
- pour chaque non-membre de données statiques de X qui est de type classe (ou un tableau), le constructeur sélectionné pour copier/déplacer le membre est triviale;
sinon le copier/déplacer constructeur est non-trivial.
Fondamentalement, cela signifie que la copie ou le déplacement constructeur est trivial si il n'est pas fourni par l'utilisateur, la classe n'a rien de virtuel, et cette propriété détient de manière récursive pour tous les membres de la classe et de la classe de base.
La définition d'un banal copier/déplacer opérateur d'affectation est très similaire, il suffit de remplacer le mot "constructeur" avec "opérateur d'affectation".
Un trivial destructeur a aussi une définition similaire, avec la contrainte qu'il ne peut pas être virtuel.
Et encore une autre règle similaire existe pour trivial constructeurs par défaut, avec l'ajout d'un constructeur par défaut n'est pas négligeable si la classe a non-membres de données statiques avec corset ou égal initialiseurs, qui nous l'avons vu ci-dessus.
Voici quelques exemples pour tout clair:
// empty classes are trivial
struct Trivial1 {};
// all special members are implicit
struct Trivial2 {
int x;
};
struct Trivial3 : Trivial2 { // base class is trivial
Trivial3() = default; // not a user-provided ctor
int y;
};
struct Trivial4 {
public:
int a;
private: // no restrictions on access modifiers
int b;
};
struct Trivial5 {
Trivial1 a;
Trivial2 b;
Trivial3 c;
Trivial4 d;
};
struct Trivial6 {
Trivial2 a[23];
};
struct Trivial7 {
Trivial6 c;
void f(); // it's okay to have non-virtual functions
};
struct Trivial8 {
int x;
static NonTrivial1 y; // no restrictions on static members
}
struct Trivial9 {
Trivial9() = default; // not user-provided
// a regular constructor is okay because we still have default ctor
Trivial9(int x) : x(x) {};
int x;
}
struct NonTrivial1 : Trivial 3 {
virtual f(); // virtual members make non-trivial ctors
}
struct NonTrivial2 {
NonTrivial2() : z(42) {} // user-provided ctor
int z;
}
struct NonTrivial3 {
NonTrivial3(); // user-provided ctor
int w;
}
NonTrivial3::NonTrivial3() = default; // defaulted but not on first declaration
// still counts as user-provided
struct NonTrivial5 {
virtual ~NonTrivial5(); // virtual destructors are not trivial
};
Standard-layout est la deuxième propriété. La norme mentionne le fait que ceux-ci sont utiles pour communiquer avec les autres langues, c'est parce qu'un standard-classe de mise en page a la même disposition de la mémoire de l'équivalent C struct ou union.
C'est une autre propriété qui doit tenir de manière récursive pour les membres et de toutes les classes de base. Et comme d'habitude, pas de fonctions virtuelles ou virtuel classes de base sont autorisés. Qui permettrait de faire la mise en page incompatible avec C.
Une ambiance détendue, la règle ici est que les classes de layout doit disposer de tous les non-membres de données statiques avec le même contrôle d'accès. Auparavant, ils devaient être tous les publics, mais maintenant vous pouvez les rendre privés ou protégés, aussi longtemps qu'ils sont tous privés ou tous protégés.
Lors de l'utilisation de l'héritage, une seule classe dans l'ensemble de l'arbre d'héritage peuvent avoir des non-membres de données statiques, et le premier non-membre de données statiques ne peuvent pas être d'une classe de base type (cela pourrait briser aliasing règles), sinon, ce n'est pas un standard-classe de mise en page.
C'est la façon dont la définition va dans le texte standard:
Standard-layout classe est une classe qui:
- n'a pas non données membres statiques de type non-standard-classe de mise en page (ou un tableau de ce type) ou de référence,
- n'a pas de fonctions virtuelles (10.3) et pas de virtuel classes de base (10.1),
- a la même contrôle d'accès (Clause 11) pour tous les non-membres de données statiques,
- n'a pas non standard-layout classes de base,
- soit n'a pas de non-membres de données statiques dans la plupart de la classe dérivée et au plus une classe de base avec non-membres de données statiques, ou n'a pas de classes de base avec les données membres statiques, et
- n'a pas de classes de base du même type que le premier non-membre de données statiques.
Standard-layout struct est un standard-classe de mise en page définie avec la classe-clé struct ou la classe-classe de clé.
Un modèle de mise en page de l'union est un standard-classe de mise en page définie avec la classe-clé de l'union.
[ Note: Standard-layout classes sont utiles pour communiquer avec le code écrit dans d'autres langages de programmation. Leur mise en page est spécifié dans la version 9.2.-la note de fin ]
Et nous allons voir quelques exemples.
// empty classes have standard-layout
struct StandardLayout1 {};
struct StandardLayout2 {
int x;
};
struct StandardLayout3 {
private: // both are private, so it's ok
int x;
int y;
};
struct StandardLayout4 : StandardLayout1 {
int x;
int y;
void f(); // perfectly fine to have non-virtual functions
};
struct StandardLayout5 : StandardLayout1 {
int x;
StandardLayout1 y; // can have members of base type if they're not the first
};
struct StandardLayout6 : StandardLayout1, StandardLayout5 {
// can use multiple inheritance as long only
// one class in the hierarchy has non-static data members
};
struct StandardLayout7 {
int x;
int y;
StandardLayout7(int x, int y) : x(x), y(y) {} // user-provided ctors are ok
};
struct StandardLayout8 {
public:
StandardLayout8(int x) : x(x) {} // user-provided ctors are ok
// ok to have non-static data members and other members with different access
private:
int x;
};
struct StandardLayout9 {
int x;
static NonStandardLayout1 y; // no restrictions on static members
};
struct NonStandardLayout1 {
virtual f(); // cannot have virtual functions
};
struct NonStandardLayout2 {
NonStandardLayout1 X; // has non-standard-layout member
};
struct NonStandardLayout3 : StandardLayout1 {
StandardLayout1 x; // first member cannot be of the same type as base
};
struct NonStandardLayout4 : StandardLayout3 {
int z; // more than one class has non-static data members
};
struct NonStandardLayout5 : NonStandardLayout3 {}; // has a non-standard-layout base class
Avec ces nouvelles règles beaucoup plus de types peut être Gousses maintenant. Et même si un type n'est pas POD, nous pouvons profiter de quelques-uns de la GOUSSE de propriétés séparément (si c'est seulement un de banal ou standard-layout).
La bibliothèque standard a les traits de tester ces propriétés dans l'en-tête <type_traits>
:
template <typename T>
struct std::is_pod;
template <typename T>
struct std::is_trivial;
template <typename T>
struct std::is_trivially_copyable;
template <typename T>
struct std::is_standard_layout;
pouvez vous s'il vous plaît élaborer des règles suivantes:
Je vais essayer:
a) standard-layout classes doivent avoir tous les non-membres de données statiques avec le même contrôle d'accès
C'est simple: tous les non-membres de données statiques doivent tous être
public
,private
ouprotected
. Vous ne pouvez pas avoir quelques -public
et certainsprivate
.Le raisonnement pour eux va pour le raisonnement pour avoir une distinction entre le "modèle standard" et "non standard de mise en page". À savoir, donner le compilateur de la liberté de choisir la façon de mettre les choses en mémoire. Ce n'est pas seulement à propos de vtable des pointeurs.
Quand ils ont normalisé C++ en 98, ils avaient pour l'essentiel à prédire comment les gens allaient le mettre en œuvre. Alors qu'ils avaient tout à fait un peu de mise en œuvre de l'expérience avec les différentes versions de C++, ils n'étaient pas certaines choses. Ils ont donc décidé de faire preuve de prudence: donner les compilateurs autant de liberté que possible.
C'est pourquoi la définition de la POD en C++98 est aussi stricte. Il a donné des compilateurs C++ d'une grande latitude aux etats de mise en page pour la plupart des classes. Fondamentalement, POD types étaient destinés à être des cas particuliers, quelque chose que vous spécifiquement écrit pour une raison.
Quand le C++11 est en cours d'élaboration, ils avaient beaucoup plus d'expérience avec les compilateurs. Et ils se sont rendu compte que... compilateur C++ les écrivains sont vraiment paresseux. Ils avaient tous cette liberté, mais ils n'ont pas à faire quelque chose avec elle.
Les règles de mise en page standard, sont plus ou moins la codification de la pratique courante: la plupart des compilateurs n'ont pas à changer grand-chose, sinon rien du tout pour les mettre en œuvre (en dehors peut-être quelques trucs pour le type correspondant de traits).
Maintenant, quand il est venu à l'
public
/private
, les choses sont différentes. La liberté de réorganiser les membres qui participentpublic
vsprivate
qui en fait peut importe pour le compilateur, en particulier dans le débogage de builds. Et depuis le point de standard de mise en page est qu'il y a la compatibilité avec d'autres langues, vous ne pouvez pas avoir la mise en page différents dans le debug contre la libération.Ensuite, il ya le fait qu'il n'a pas vraiment de mal à l'utilisateur. Si vous effectuez un encapsulé classe, les chances sont bonnes que toutes vos données membres sera
private
de toute façon. Vous n'avez généralement pas exposer les données publiques des membres entièrement encapsulé types. Donc, ce ne serait qu'un problème pour les quelques utilisateurs qui ne veulent faire que, de la qui veulent que la division.Donc c'est pas une grosse perte.
b) d'une seule classe dans l'ensemble de l'arbre d'héritage peuvent avoir des non-membres de données statiques,
La raison pour cela on en revient à la raison normalisé standard de mise en page nouveau: la pratique courante.
Il n'y a pas de pratique courante quand il s'agit d'avoir deux membres d'un arbre d'héritage qui en fait stocker des choses. Certains mettent de la classe de base avant de la dérivée, d'autres le font dans l'autre sens. De quelle manière avez-vous les membres s'ils sont issus de deux classes de base? Et ainsi de suite. Les compilateurs divergent grandement sur ces questions.
Aussi, grâce à la zéro/un/l'infini de la règle, une fois que vous dites que vous pouvez avoir deux classes avec les membres, vous pouvez dire autant que vous le souhaitez. Cela nécessite l'ajout d'un grand nombre de règles de présentation pour savoir comment gérer cela. Que vous avez à dire comment l'héritage multiple, les œuvres, les classes qui mettent leurs données avant d'autres classes, etc. C'est beaucoup de règles, pour très peu de gain matériel.
Vous ne pouvez pas faire tout ce qui ne disposent pas de fonctions virtuelles et un constructeur par défaut de mise en page standard.
et le premier non-membre de données statiques ne peuvent pas être d'une classe de base type (cela pourrait briser aliasing règles).
Je ne peux pas vraiment parler de celui-ci. Je ne suis pas suffisamment instruits en C++de l'aliasing règles de vraiment les comprendre. Mais il a quelque chose à voir avec le fait que la base de membres partagent la même adresse que la classe de base lui-même. C'est:
struct Base {}; struct Derived : Base { Base b; }; Derived d; static_cast<Base*>(&d) == &d.b;
Et c'est sans doute à l'encontre de C++de l'aliasing règles. D'une certaine façon.
Cependant, pensez à ceci: quelle utilité pourrait avoir la capacité de faire cela jamais fait ? Depuis seulement une classe peut avoir des non-membres de données statiques, alors
Derived
doit être la classe (car il a unBase
en tant que membre). Donc,Base
doit être vide (de données). Et siBase
est vide, ainsi que d'une classe de base... pourquoi un membre de données de tout?Depuis
Base
est vide, il n'a pas d'état. De sorte que toute non-fonctions membres statiques vont faire ce qu'ils en fonction de leurs paramètres, pas de leurthis
pointeur.Donc encore une fois: pas de grosse perte.
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.