只是一个问题,我自己的好奇心。我多次听说在编写方法时最好使用复制/销毁范例。所以如果你有这样的方法:
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
的全部费用?
我意识到所有编译器都是不同的,而这取决于编译器认为这个代码是最优的。我只是笼统地说,大多数编译最有可能回应?我很好奇这种优化是如何完成的。
答案 0 :(得分:2)
for(int i=0; i<10; i++){
list.push_back(myClass.getObject());
}
编译器是否会在堆栈上放置10个OtherClass实例,以便它可以内联此方法并避免在未经优化的代码中发生的复制和破坏?
它不需要需要将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 :(得分:1)
这取决于os。
上哪个编译器的版本为什么不让编译器输出它的程序集,你可以自己看看。
gcc - http://www.delorie.com/djgpp/v2faq/faq8_20.html
visual studio - Viewing Assembly level code from Visual C++ project
答案 2 :(得分:1)
通常,只要结果程序的行为没有明显改变,优化编译器就可以对代码进行任何的更改。这包括inline
函数(或不包括),即使该函数未被程序员标记为inline
。
答案 3 :(得分:0)
编译器唯一需要关心的是程序行为。如果优化使程序逻辑和数据保持完整,则优化是 legal 。 (所有可能的程序输入)必须以与没有选择的方式相同的方式出现(所有可能的程序输出)。
这种特定的优化是否可行(肯定是,它是否是一个真正的优化是不同的东西!)取决于目标平台指令集以及是否可行实现它。