假设没有编译器优化。将创建OutputBuffer_s类型对象多少次?
#include <iostream>
#include <vector>
struct OutputBuffer_s {
int encoded[10];
};
OutputBuffer_s func() {
OutputBuffer_s s;
return s;
}
int main() {
OutputBuffer_s a = func();
}
最初,我假设过三次。
1)调用func()时,将在堆栈上创建对象s
。
2)当func()超出范围时,它将把对象s
的副本返回给main()。
3)将值复制到main()中的对象a
上,因为func()返回的值是临时的。
我知道我在这里是错的,因为我在-O0
中使用g++
进行了编译,但是在覆盖构造函数之后,我只能看到一个创建。我想知道我在哪里以及为什么错了。
答案 0 :(得分:6)
您在这里拥有copy-elison。
省略复制和移动(自C ++ 11起)构造函数,从而产生零复制传递值语义。
即使使用route('jobs.jobssearch');
选项,GCC也可以取消构造函数。这就是这里发生的事情。如果要专门防止省略,则可以使用-O0
选项。
如果使用此选项,则C ++ 11将有一个构造函数调用和两个move构造函数调用。
请参见demo here.
如果使用C ++ 17,则在某些情况下可以保证复制删除,即使使用-fno-elide-constructors
选项,此处也会有一个构造函数调用,而只有一个移动构造函数调用。
请参见demo here.
答案 1 :(得分:2)
C ++ 17引入了临时实现,我引用:
可以将任何完整类型T的prvalue转换为相同类型T的xvalue。此转换通过将临时对象作为其结果对象来评估prvalue,从而从prvalue初始化类型T的临时对象。表示临时对象的xvalue。如果T是一个类或类类型的数组,则它必须具有一个可访问且未删除的析构函数。
在这种情况下,对构造器的额外调用将成为移动操作。在C ++ 17之前,复制省略不是强制性的,编译器会通常复制elide。据我所知,在您的情况下,编译器仍然会复制elide(尝试使用godbolt并检查生成的程序集)。
要完全回答,请一次调用构造函数,然后执行一次动作。