编译器可以内联在循环内生成对象的方法吗?

问题描述 投票:0回答:4

只是出于我自己的好奇心提出的问题。 我多次听说编写方法时最好使用复制/销毁范例。 所以如果你有这样的方法:

OtherClass MyClass::getObject(){
    OtherClass returnedObject;
    return returnedObject;
}

据说编译器将通过本质上内联方法并在调用

getObject
的方法的堆栈上生成类来对此进行优化。 我想知道在这样的循环中它是如何工作的

for(int i=0; i<10; i++){
    list.push_back(myClass.getObject());
}

编译器是否会将 10 个

OtherClass
实例放入堆栈中,以便可以内联此方法并避免在未优化的代码中发生的复制和销毁? 像这样的代码怎么样:

while(!isDone){
     list.push_back(myClass.getObject());
    //other logic which decides rather or not to set isDone
}

在这种情况下,编译器不可能知道

getObject
将被调用多少次,因此推测它可以向堆栈预先分配任何内容,所以我的假设是没有完成内联,每次调用该方法时我都会付费复制的全部费用
OtherObject

我意识到所有编译器都是不同的,这取决于编译器是否认为该代码是最佳的。 我只是笼统地说,大多数编译最有可能如何响应? 我很好奇这种优化是如何完成的。

c++ optimization
4个回答
2
投票
for(int i=0; i<10; i++){
    list.push_back(myClass.getObject());
}

编译器是否会将 OtherClass 的 10 个实例放入堆栈中,以便可以内联此方法并避免在未优化的代码中发生的复制和销毁?

不需要将 10 个实例放在堆栈上只是为了避免复制和销毁...如果有空间供一个对象返回(带或不带返回值优化),那么它可以重复使用该空间 10 次 -每次通过列表push_back从相同的堆栈空间复制到一些新的堆分配的内存。

编译器甚至有权分配新内存并安排 myClass.getObject() 直接在该内存中构造对象。

此外,如果优化器选择展开循环,它可能会调用 myClass.getObject() 10 次 - 即使有一些重叠或并行性 - 如果它能以某种方式说服自己这会产生相同的总体结果。 在这种情况下,它确实需要 10 个返回对象的空间,这又取决于编译器是否在堆栈上,或者通过一些神奇的聪明的优化,直接在堆内存中。

在实践中,我希望编译器需要从堆栈复制到堆 - 我非常怀疑任何主流编译器是否足够聪明,可以在堆内存中安排直接构造。 不过,循环展开和 RVO 是常见的优化。 但是,即使两者都启动,我希望每次调用 getObject 都能在堆栈上串行构造一个结果,然后将其复制到堆中。

如果您想“了解”,请编写一些代码来测试您自己的编译器。 您可以让构造函数写出“this”指针值。

像这样的代码怎么样:

while(!isDone){ list.push_back(myClass.getObject()); //other logic which decides rather or not to set isDone }

代码越复杂、越不惯用,编译器编写者就越不可能并且不厌其烦地对其进行优化。 在这里,您甚至没有向我们展示我们可以推测的复杂程度。 尝试一下您的编译器和优化设置,看看......


1
投票
这取决于哪个操作系统上哪个版本的编译器。

为什么不让你的编译器输出它的程序集,你可以自己看一下。

gcc -

http://www.delorie.com/djgpp/v2faq/faq8_20.html

Visual Studio -

查看 Visual C++ 项目中的汇编级代码


1
投票
一般来说,优化编译器可以对代码进行

任何更改,只要生成的程序的行为没有明显改变。 这包括(或不)inline

ing 函数,即使该函数没有被程序员标记为
inline


0
投票
编译器唯一需要关心的是程序行为。如果优化保持程序逻辑和数据完整,则优化是

合法。进去的东西(所有可能的程序输入),必须以与没有优化的方式相同的方式出来(所有可能的程序输出)。

这种特定的优化是否可能(当然是,是否是实际的

优化是不同的事情!)取决于目标平台指令集以及是否可行。

© www.soinside.com 2019 - 2024. All rights reserved.