C'est plus subtil que ne le suggèrent les autres réponses. Il n'y a pas de division absolue entre les données sur la pile et les données sur le tas en fonction de la façon dont vous les déclarez. Par exemple:
std::vector<int> v(10);
Dans le corps d'une fonction, cela déclare un vector
(tableau dynamique) de dix entiers sur la pile. Mais le stockage géré par le vector
n'est pas sur la pile.
Ah, mais (les autres réponses suggèrent) la durée de vie de ce stockage est limitée par la durée de vie de vector
lui - même, qui ici est basée sur la pile, donc cela ne fait aucune différence comment il est implémenté - nous ne pouvons le traiter que comme un objet basé sur la pile avec une sémantique de valeur.
Non. Supposons que la fonction soit:
void GetSomeNumbers(std::vector<int> &result)
{
std::vector<int> v(10);
// fill v with numbers
result.swap(v);
}
Ainsi, tout ce qui a une swap
fonction (et tout type de valeur complexe devrait en avoir une) peut servir de sorte de référence rebindable à certaines données de tas, sous un système qui garantit un seul propriétaire de ces données.
Par conséquent, l'approche C ++ moderne consiste à ne jamais stocker l'adresse des données de tas dans des variables de pointeur local nues. Toutes les allocations de tas doivent être cachées à l'intérieur des classes.
Si vous faites cela, vous pouvez penser à toutes les variables de votre programme comme s'il s'agissait de types de valeurs simples, et oublier complètement le tas (sauf lors de l'écriture d'une nouvelle classe wrapper de type valeur pour certaines données de tas, ce qui devrait être inhabituel) .
Vous devez simplement conserver un peu de connaissances spéciales pour vous aider à optimiser: si possible, au lieu d'assigner une variable à une autre comme ceci:
a = b;
échangez-les comme ceci:
a.swap(b);
parce que c'est beaucoup plus rapide et ne lance pas d'exceptions. La seule exigence est que vous n'ayez pas besoin b
de continuer à conserver la même valeur (elle obtiendra a
la valeur de à la place, qui sera supprimée a = b
).
L'inconvénient est que cette approche vous oblige à renvoyer les valeurs des fonctions via les paramètres de sortie au lieu de la valeur de retour réelle. Mais ils corrigent cela en C ++ 0x avec des références rvalue .
Dans les situations les plus compliquées de toutes, vous prendriez cette idée à l'extrême général et utiliseriez une classe de pointeur intelligent telle que celle shared_ptr
qui est déjà dans tr1. (Bien que je soutienne que si vous semblez en avoir besoin, vous avez peut-être quitté le point idéal de l'applicabilité du C ++ standard.)