63 votes

Le compilateur peut-il optimiser l'allocation de tas en piles?

Aussi loin que les optimisations du compilateur aller, est-il légal et/ou possible de changer un tas attribution d'une allocation de pile? Ou serait-ce casser la comme-si la règle?

Par exemple, dire que c'est la version originale du code

{
    Foo* f = new Foo();
    f->do_something();
    delete f;
}

Serait un compilateur être en mesure de la changer pour la suite

{
    Foo f{};
    f.do_something();
}

Je ne le pense pas, parce que cela aurait des conséquences si la version originale a été en s'appuyant sur des choses comme la coutume allocateurs. La norme de dire quoi que ce soit à ce sujet?

51voto

geza Points 13730

Oui, c'est légal. expr.new/10 de C++14:

Une mise en œuvre est permis d'omettre un appel à une remplaçable mondiale fonction d'allocation (18.6.1.1, 18.6.1.2). Quand il le fait, le stockage est fourni par la mise en œuvre ou prévues par l'extension de l' l'allocation d'une nouvelle expression.

expr.delete/7:

Si la valeur de l'opérande de la suppression de l'expression n'est pas un null la valeur du pointeur, puis:

- Si l'appel d'allocation pour la nouvelle expression de l'objet à supprimé n'a pas été omis et l'allocation n'a pas été prolongé (5.3.4), la suppression de l'expression doit appeler une fonction de libération (3.7.4.2). La valeur renvoyée par l'appel d'allocation de la nouvelle expression doit être passé comme premier argument de la fonction de libération.

- Sinon, si l'allocation a été étendu ou par l'extension de l'allocation d'une nouvelle expression, et la supprimer expression pour tous les autres pointeur de la valeur produite par une nouvelle expression, qui avait de stockage fourni par l'extension des nouvelle expression a été évaluée, la suppression de l'expression doit convoquer une la fonction de libération. La valeur renvoyée par l'appel d'allocation de la nouvelle-expression doit être passé comme premier argument la fonction de libération.

- Dans le cas contraire, la suppression de l'expression n'ira pas en appel d'une libération de la mémoire fonction (3.7.4.2).

Donc, en résumé, il est permis de remplacer new et delete avec quelque chose de mise en œuvre définies, comme l'utilisation de la pile au lieu de tas.

Remarque: Comme Massimiliano Janes commentaires, le compilateur pourrait pas coller exactement à cette transformation, à votre exemple, si do_something jette: le compilateur doit laisser de côté destructeur de l'appel d' f dans ce cas (alors que votre transformé échantillon n'appeler le destructeur dans ce cas). Mais autre que cela, il est libre de le mettre f dans la pile.

6voto

lorro Points 1220

Ce ne sont pas équivalents. f.do_something() peut être lancé, auquel cas le premier objet reste en mémoire, le second est détruit.

4voto

Daniel Jour Points 6551

Je tiens à souligner quelque chose de l'OMI pas assez souligné dans les autres réponses:

struct Foo {
    static void * operator new(std::size_t count) {
        std::cout << "Hey ho!" << std::endl;
        return ::operator new(count);
    }
};

Une allocation new Foo() ne peuvent généralement pas être remplacé, car:

Une mise en œuvre est permis d'omettre un appel à une remplaçable globales fonction d'allocation (18.6.1.1, 18.6.1.2). Quand il le fait, le stockage est fourni par la mise en œuvre ou prévues par l'extension de l'allocation d'une nouvelle expression.

Ainsi, comme dans l' Foo exemple ci-dessus, l' Foo::operator new doit être appelé. L'omission de cet appel serait de changer le comportement observable du programme.

L'exemple du monde réel: Foos pourriez avoir besoin de résider dans certains particulière de la mémoire de la région (comme la mémoire mappée IO) pour fonctionner correctement.

Prograide.com

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.

Powered by:

X