Pourquoi est une GOUSSE dans une struct initialisé à zéro par un constructeur implicite lors de la création d'un objet dans le tas ou un objet temporaire dans la pile?
La norme et la C++ livre dire que le constructeur par défaut pour le type de classe des membres est convoquée par le implicites générées constructeur par défaut, mais des types intégrés ne sont pas initialisés. Cependant, dans cet essai, programme, j'obtiens des résultats inattendus lors de l'allocation d'un objet dans le tas ou lors de l'utilisation d'un objet temporaire:
#include<iostream>
struct Container
{
int n;
};
int main()
{
Container c;
std::cout << "[STACK] Num: " << c.n << std::endl;
Container *pc = new Container();
std::cout << "[HEAP] Num: " << pc->n << std::endl;
delete pc;
Container tc = Container();
std::cout << "[TEMP] Num: " << tc.n << std::endl;
}
J'obtiens ce résultat:
[STACK] Num: -1079504552
[HEAP] Num: 0
[TEMP] Num: 0
Ce n'est pas de compilateur spécifique de comportement? Je n'ai pas vraiment l'intention de s'appuyer sur cela, mais je suis curieux de savoir pourquoi cela se produit, spécialement pour le troisième cas.
- double possible de par Défaut Struct Initialisation en C++
- j'imagine que le segment en lui-même est initialisé avec des zéros
- Je pensais la même chose sur le tas de cas, peut-être que c'était juste des zéros par hasard, mais je trouve l'objet temporaire en cas surprenant.
- voir le lien posté par @acéré, il a l'explication de la temp cas
- La plupart des systèmes d'exploitation en tant que mesure de sécurité est égal à zéro des pages de la mémoire avant de les manipuler à un processus (pour éviter un processus d'être en mesure d'inspecter les autres processus de la mémoire). Le résultat de ceci est que, le plus souvent, un simple cas de test qui vient de mallocs va de l'initialisation de la mémoire (pas vraiment, mais il va ressembler), tandis que la pile a plus de chances d'être modifiés par les précédents appels de fonction.
Vous devez vous connecter pour publier un commentaire.
C'est un comportement attendu. Il y a deux concepts, "initialisation par défaut" et "initialisation de la valeur". Si vous ne mentionnez pas tout initialiseur, l'objet est initialisé par défaut", alors que si vous faites mention, de même qu' () pour le constructeur par défaut, l'objet est "la valeur initialisée". Lorsque le constructeur n'est défini, les deux cas d'appel de constructeur par défaut. Mais pour les types intégrés, "initialisation de la valeur" zéros de la mémoire alors que "initialisation par défaut" ne fonctionne pas.
Ainsi, lorsque vous initialisez:
il va appeler le constructeur par défaut si l'un est fourni, mais les types primitifs seront pas initialisés. Toutefois, lorsque vous mentionnez un initialiseur, par exemple
un type primitif (ou primitif membres d'une structure) sera la VALEUR d'initialisation.
De même pour:
si vous définissez le constructeur
le x membre seront pas initialisés, mais si vous définir le constructeur
ça sera la VALEUR d'initialisation. Qui s'applique à
new
, ainsidevrait vous donner à la mémoire non initialisée, mais
devrait vous donner de la mémoire initialisé à zéro.
Malheureusement la syntaxe:
n'est pas autorisé en raison de la grammaire de l'ambiguïté et de
est obligé d'appeler le constructeur par défaut suivie par le constructeur par copie si ils sont à la fois déterminés et non inlineable.
C++11 introduit une nouvelle syntaxe,
qui est utilisable pour les deux cas. Si vous êtes toujours coincé avec le plus ancien, c'est pourquoi il est Boost.ValueInitialized, de sorte que vous pouvez initialiser correctement l'instance de l'argument de modèle.
Discussion plus détaillée peut être trouvée par exemple dans Boost.ValueInitialized documentation.
La réponse courte est: le vide parenthèse effectuer la valeur d'initialisation.
Quand vous dites
Container *pc = new Container;
au lieu de cela, vous pourrez observer des comportements différents.struct test { int x; }; void foo() { test t; std::cout << t.x << std::endl; ++t.x; } int main() { foo(); foo(); foo(); }
Le modèle courant (si le compilateur n'a pas inline) est quet
sera créé dans la même position de mémoire dans les appels consécutifs, la première fois, il sera probablement0
, mais alors il va changer. Si le code n'initialiser, vous obtenez toujours0
dans tous les appels.t
les objets ne sont pas placés au même endroit dans la pile:).for (int i =0; i < 1000000000; ++i ) { foo(); }
. Chaque appel àfoo()
aura son propre bouchée de la pile, et il sera libéré lorsque la fonction retourne (généralement de l'appelant, mais c'est un détail d'implémentation). Appels consécutifs de la même fonction, doit réutiliser la même pièce de la pile. Avez-vous ajouter du code pour le test? Quel compilateur que vous utilisez? Le code ci-dessus montre les résultats attendus dans g++.foo();foo()
) permettra de générer de 2 appels de fonction.De sorte que votre nouveau code n'est pas égale à la précédente. Celui-ci fonctionnera de manière à ce que, tandis que l'un ne le sera pas. J'utilise g++ aussi.