只是出于我自己的好奇心提出的问题。 我多次听说编写方法时最好使用复制/销毁范例。 所以如果你有这样的方法:
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
?
我意识到所有编译器都是不同的,这取决于编译器是否认为该代码是最佳的。 我只是笼统地说,大多数编译最有可能如何响应? 我很好奇这种优化是如何完成的。
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
}
代码越复杂、越不惯用,编译器编写者就越不可能并且不厌其烦地对其进行优化。 在这里,您甚至没有向我们展示我们可以推测的复杂程度。 尝试一下您的编译器和优化设置,看看......
任何更改,只要生成的程序的行为没有明显改变。 这包括(或不)inline
ing 函数,即使该函数没有被程序员标记为
inline
。
合法。进去的东西(所有可能的程序输入),必须以与没有优化的方式相同的方式出来(所有可能的程序输出)。
这种特定的优化是否可能(当然是,是否是实际的优化是不同的事情!)取决于目标平台指令集以及是否可行。