Can the compiler optimize from heap to stack allocation?

断了今生、忘了曾经 提交于 2021-02-05 14:24:01

问题


As far as compiler optimizations go, is it legal and/or possible to change a heap allocation to a stack allocation? Or would that break the as-if rule?

For example, say this is the original version of the code

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

Would a compiler be able to change this to the following

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

I wouldn't think so, because that would have implications if the original version was relying on things like custom allocators. Does the standard say anything specifically about this?


回答1:


Yes, it's legal. expr.new/10 of C++14:

An implementation is allowed to omit a call to a replaceable global allocation function (18.6.1.1, 18.6.1.2). When it does so, the storage is instead provided by the implementation or provided by extending the allocation of another new-expression.

expr.delete/7:

If the value of the operand of the delete-expression is not a null pointer value, then:

— If the allocation call for the new-expression for the object to be deleted was not omitted and the allocation was not extended (5.3.4), the delete-expression shall call a deallocation function (3.7.4.2). The value returned from the allocation call of the new-expression shall be passed as the first argument to the deallocation function.

— Otherwise, if the allocation was extended or was provided by extending the allocation of another new- expression, and the delete-expression for every other pointer value produced by a new-expression that had storage provided by the extended new-expression has been evaluated, the delete-expression shall call a deallocation function. The value returned from the allocation call of the extended new-expression shall be passed as the first argument to the deallocation function.

— Otherwise, the delete-expression will not call a deallocation function (3.7.4.2).

So, in summary, it's legal to replace new and delete with something implementation defined, like using the stack instead of heap.

Note: As Massimiliano Janes comments, the compiler could not stick exactly to this transformation for your sample, if do_something throws: the compiler should omit destructor call of f in this case (while your transformed sample does call the destructor in this case). But other than that, it is free to put f into the stack.




回答2:


These are not equivalent. f.do_something() might throw, in which case the first object remains in memory, the second gets destructed.




回答3:


I'd like to point out something IMO not stressed enough in the other answers:

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

An allocation new Foo() cannot generally be replaced, because:

An implementation is allowed to omit a call to a replaceable global allocation function (18.6.1.1, 18.6.1.2). When it does so, the storage is instead provided by the implementation or provided by extending the allocation of another new-expression.

Thus, like in the Foo example above, the Foo::operator new needs to be called. Omitting this call would change the observable behavior of the program.

Real world example: Foos might need to reside in some special memory region (like memory mapped IO) to function properly.



来源:https://stackoverflow.com/questions/47075871/can-the-compiler-optimize-from-heap-to-stack-allocation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!