Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 编译器能否从堆到堆栈分配进行优化?_C++_Memory Management_Language Lawyer_Compiler Optimization - Fatal编程技术网

C++ 编译器能否从堆到堆栈分配进行优化?

C++ 编译器能否从堆到堆栈分配进行优化?,c++,memory-management,language-lawyer,compiler-optimization,C++,Memory Management,Language Lawyer,Compiler Optimization,就编译器优化而言,将堆分配更改为堆栈分配是否合法和/或可能?或者这会打破僵局吗 例如,假设这是代码的原始版本 { Foo* f = new Foo(); f->do_something(); delete f; } 编译器是否能够将其更改为以下内容 { Foo f{}; f.do_something(); } 我不这么认为,因为如果原始版本依赖于自定义分配器之类的东西,这将产生影响。标准中有没有具体说明这一点?这些都不是等效的f.do_somet

就编译器优化而言,将堆分配更改为堆栈分配是否合法和/或可能?或者这会打破僵局吗

例如,假设这是代码的原始版本

{
    Foo* f = new Foo();
    f->do_something();
    delete f;
}
编译器是否能够将其更改为以下内容

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

我不这么认为,因为如果原始版本依赖于自定义分配器之类的东西,这将产生影响。标准中有没有具体说明这一点?

这些都不是等效的
f.do_something()
可能抛出,在这种情况下,第一个对象保留在内存中,第二个对象被销毁。

是的,这是合法的expr.new/10

允许实现省略对可替换全局变量的调用 分配功能(18.6.1.1、18.6.1.2)。执行此操作时,存储 而是由实现提供或通过扩展 另一个新表达式的分配

expr.delete/7

如果删除表达式的操作数的值不是null 指针值,然后:

-如果对象的新表达式的分配调用 删除未省略,分配未扩展(5.3.4), delete表达式应调用释放函数(3.7.4.2)。 从新表达式的分配调用返回的值 应作为第一个参数传递给解除分配函数

-否则,如果分配被延长或由 扩展另一个新表达式的分配,以及 删除由 新表达式,该表达式具有扩展 已计算新表达式,删除表达式应调用 释放函数。从的分配调用返回的值 扩展的新表达式应作为第一个参数传递给 释放函数

-否则,删除表达式将不会调用解除分配 功能(3.7.4.2)

总之,用实现定义的东西替换
new
delete
是合法的,比如使用堆栈而不是堆


注意:正如Massimiliano Jane的评论,编译器无法准确地为您的示例执行此转换,如果
do_something
抛出:在这种情况下,编译器应该省略
f
的析构函数调用(而在这种情况下,转换后的示例确实调用析构函数)。但除此之外,它可以自由地将
f
放入堆栈。

我想指出一些我在其他答案中没有强调的问题:

struct Foo {
    static void * operator new(std::size_t count) {
        std::cout << "Hey ho!" << std::endl;
        return ::operator new(count);
    }
};
structfoo{
静态void*运算符新(std::size\u t count){

std::cout No,那太过分了。堆栈使用率的增长是一个大问题,他们确实以它命名了一个流行的编程网站。相关:Clang确实优化了这个iff,它可以内联调用的函数(+函数体上的某些条件).从tobi303提到的链接来看,自c++14以来,情况发生了变化,请参见];从c++14开始,编译器可以在堆栈中存储Foo,只要它能够证明相同的行为(例如,没有任何东西被抛出do_something)值得注意的是,声明函数
noexcept
对gcc和clang的优化器没有帮助,但函数体显示clang却有帮助。这可能还有更多。@BaummitAugen,如果你问“编译器为什么不执行此优化?”我认为还有更多:当有人编写一个新表达式时,他们需要动态分配。如果他们需要堆栈分配,他们应该编写
Foo f{}
。这是有正当理由的,编译器无法知道,例如,可能他们在valgrind下运行,想要跟踪所有堆的使用情况,或者他们正在调试堆碎片问题。编译器必须在允许的优化和程序员真正想要的之间取得平衡。编译器应该是朋友,而不是朋友问题的一个关键是,即使使用了
new
,分配是否也可以在堆栈上。如果我理解正确,它将始终是动态内存,而不会在堆栈上。给定的段落说,分配的大小可以扩展到更大的动态内存块,或者使用以前的动态内存扩展。@SHR:我强调了“存储由实现提供”。它可以是任何东西,甚至是堆栈。这些更改的背景在我对