2008-08-27 11 views
4

Dans mes Explorations parmi Internet, je suis tombé sur this post, qui comprend ceC++ - Que signifie "Stack automatique"?

« (bien écrit) C++ va très longueurs pour faire empiler des objets automatiques fonctionnent « comme » primitives, comme en témoigne dans les conseils de Stroustrup à « faire comme les ints font » Cela nécessite une beaucoup plus grande adhésion aux principes du développement Orienté objet :. votre classe ne va pas jusqu'à ce qu'il « fonctionne comme » un int, suite à la " Règle de Trois "que guara Il peut être créé, copié, et correctement détruit comme une pile automatique. "

J'ai fait un peu de code C et C++, mais en passant, jamais rien de grave, mais je suis juste curieux, qu'est-ce que cela signifie exactement?

Quelqu'un peut-il donner un exemple?

Répondre

12

Les objets de pile sont gérés automatiquement par le compilateur.

Lorsque l'étendue est laissée, elle est supprimée.

{ 
    obj a; 
} // a is destroyed here 

Lorsque vous faites la même chose avec un objet « newed » vous obtenez une fuite de mémoire:

{ 
    obj* b = new obj; 
} 

b ne soit pas détruit, donc nous avons perdu la capacité de récupérer la mémoire b est propriétaire. Et peut-être pire, l'objet ne peut pas se nettoyer.

En C ce qui suit est commun:

{ 
    FILE* pF = fopen(...); 
    // ... do sth with pF 
    fclose(pF); 
} 

En C++ nous écrivons ceci:

{ 
    std::fstream f(...); 
    // do sth with f 
} // here f gets auto magically destroyed and the destructor frees the file 

Quand on oublie d'appeler fclose dans l'échantillon C le fichier est fermé et ne peut être utilisé par d'autres programmes. (par exemple, il ne peut pas être supprimé).

Un autre exemple, illustrant la chaîne d'objet, qui peut être construite, assignée à et qui est détruite à la sortie de la portée.

{ 
    string v("bob"); 
    string k; 

    v = k 
    // v now contains "bob" 
} // v + k are destroyed here, and any memory used by v + k is freed 
+0

Cette fonctionnalité est largement utilisée en C++ pour gérer automatiquement l'acquisition et la libération des ressources, via l'idiome RAII (Resource Acquisition Is Initialization). –

+0

for completeness: http://en.wikipedia.org/wiki/RAII –

+0

Juste un problème de libellé mineur: Chaque variable est détruite quand sa portée/durée de vie est épuisée, donc, en fait, le 'obj * b' est" détruit ". Son destructeur ne fait rien et donc le 'nouvel objectif 'n'est pas supprimé. Juste en changeant le type de pointeur, c'est à dire. 'smart_ptr ' qui a un destructeur, pas de changements de portée, mais les objets sont supprimés. – quetzalcoatl

1

Les variables en C++ peuvent être déclarées sur la pile ou sur le tas. Lorsque vous déclarez une variable en C++, elle est automatiquement placée dans la pile, sauf si vous utilisez explicitement le nouvel opérateur (il va sur le tas).

MyObject x = MyObject(params); // onto the stack 

MyObject * y = new MyObject(params); // onto the heap 

Cela fait une grande différence dans la façon dont la mémoire est gérée. Lorsqu'une variable est déclarée sur la pile, elle sera désallouée lorsqu'elle sortira de la portée. Une variable sur le tas ne sera pas détruite jusqu'à ce que delete soit explicitement appelée sur l'objet.

+0

En fait, vous voulez faire attention là-bas. Même si nous savons tous que les données globales sont mauvaises, n'oubliez pas les segments de données (initialisés) et BSS (non initialisés), où résident les données globales/statiques. – Dan

1

Les piles automatiques sont des variables affectées à la pile de la méthode en cours. L'idée derrière la conception d'une classe qui peut agir comme pile automatique est qu'il devrait être possible de l'initialiser complètement avec un appel et de le détruire avec un autre. Il est essentiel que le destructeur libère toutes les ressources allouées par l'objet et son constructeur renvoie un objet qui a été entièrement initialisé et prêt à l'emploi. De même pour l'opération de copie - la classe devrait pouvoir être facilement faite des copies, qui sont entièrement fonctionnelles et indépendantes.

L'utilisation d'une telle classe doit être similaire à la façon dont les primitives int, float, etc. sont utilisées. Vous les définissez (en leur donnant éventuellement une valeur initiale), puis vous les passez et à la fin laissez le compilateur au nettoyage.

2

Outre les autres réponses:

Le langage C++ est en fait le mot-clé auto de déclarer explicitement la classe de stockage d'un objet. Bien sûr, c'est complètement inutile car c'est la classe de stockage implicite pour les variables locales et ne peut être utilisée nulle part. Le contraire de auto est static (localement et globall).

Voici deux déclarations sont équivalentes:

int main() { 
    int a; 
    auto int b; 
} 

Parce que le mot-clé est tout à fait inutile, il sera effectivement recyclé dans la prochaine norme C de (« C++ 0x ») et obtient un nouveau sens, à savoir , il permet au compilateur de déduire le type de variable de son initialisation (comme var en C#):

auto a = std::max(1.0, 4.0); // `a` now has type double. 
1

-moi si je me trompe, mais je pense que l'opération de copie ne soit pas obligatoire pour profiter pleinement de la pile automatique nettoyage. Considérons par exemple un objet MutexGuard classique, il n'a pas besoin d'une opération de copie pour être utile comme pile automatique, ou le fait-il?

+0

C'est correct. Vous devriez toujours déclarer le constructeur de la copie privé (ou en C++ 0x, supprimé) afin d'empêcher quelqu'un de l'appeler automatiquement, ce qui conduirait à un double gratuit de la ressource possédée. La règle de trois ne dit pas que vous devez définir un constructeur de copie, il dit que vous devez empêcher le compilateur d'en définir un (soit en fournissant le vôtre soit en le rendant inaccessible/supprimé). –