2

只是出于我自己的好奇心的问题。我多次听说在编写方法时最好使用复制/销毁范式。因此,如果您有这样的方法:

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

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

4

4 回答 4

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
}

代码越复杂、越不惯用,编译器编写者就越不可能为它进行优化。在这里,您甚至没有向我们展示我们可以推测的复杂程度。试试你的编译器和优化设置,看看....

于 2012-06-22T15:18:20.797 回答
1

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

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

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

visual studio -从 Visual C++ 项目中查看程序集级代码

于 2012-06-22T14:38:25.467 回答
1

通常,优化编译器可以对您的代码进行任何更改,只要生成的程序的行为没有明显改变。这包括inlineing 函数(或不包括),即使该函数没有inline被程序员标记。

于 2012-06-22T14:39:16.103 回答
0

编译器唯一需要关心的是程序的行为。如果优化保持程序逻辑和数据完整,则优化是合法的。输入(所有可能的程序输入)必须以与没有优化相同的方式输出(所有可能的程序输出)。

这种特定的优化是否可能(当然是,是否是实际的优化是另一回事!)取决于目标平台指令集以及实现它是否可行。

于 2012-06-22T14:45:27.460 回答