假设没有编译器优化,那么将创建此对象多少次?

时间:2019-02-27 09:02:46

标签: c++ constructor copy-constructor

假设没有编译器优化。将创建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++进行了编译,但是在覆盖构造函数之后,我只能看到一个创建。我想知道我在哪里以及为什么错了。

2 个答案:

答案 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并检查生成的程序集)。

要完全回答,请一次调用构造函数,然后执行一次动作。