【问题标题】:Assuming no compiler optimization, how many times will this object be created?假设没有编译器优化,这个对象会被创建多少次?
【发布时间】:2019-02-27 09:02:46
【问题描述】:

假设没有编译器优化。 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();
}

最初,我假设了 3 次。

1) 当func()被调用时,对象s会在栈上创建。

2) 当 func() 超出范围时,它会将对象 s 的副本返回给 main()。

3) 在 main() 中将值复制到对象 a,因为 func() 返回的值将是一个临时值。

我知道我在这里错了,因为我在g++ 中使用-O0 编译,但是在覆盖构造函数后我只能看到一个创建。我想知道我在哪里以及为什么我错了。

【问题讨论】:

  • 3) a 是复制构造甚至移动构造,因为func() 返回一个右值。
  • 为什么这对你很重要?请注意as-if rule。甚至 g++-O0 也在做一些优化。
  • 您使用的是哪个版本的 C++?
  • copy elision 在 C++17 之前允许,在 C++17 之后的某些情况下是强制性的。
  • @BasileStarynkevitch "as-if" 可能适用于这种情况——但它与复制省略并不真正相关。即使省略的构造函数或析构函数有副作用,也明确允许复制省略。

标签: c++ constructor copy-constructor


【解决方案1】:

你在这里有什么copy-elison

省略复制和移动(自 C++11 起)构造函数,从而产生零复制值传递语义。

即使使用-O0 选项,GCC 也可以省略构造函数。这就是这里发生的事情。如果要专门防止省略,可以使用-fno-elide-constructors 选项。

如果使用此选项,对于 C++11,将有一个构造函数调用和两个移动构造函数调用。

demo here.

如果您使用 C++17,则在某些情况下可以保证复制省略,即使使用 -fno-elide-constructors 选项,也会有一个构造函数调用和一个移动构造函数调用。

demo here.

【讨论】:

  • 使用c++17,它归结为一个构造函数和一个动作。
  • 感谢您的解释。我会尝试阅读更多相关信息。
【解决方案2】:

C++17 引入了我引用的临时物化:

任何完整类型 T 的纯右值都可以转换为相同类型 T 的 xvalue。这种转换通过使用临时对象作为其结果对象评估纯右值,从纯右值初始化类型 T 的临时对象,并产生一个xvalue 表示临时对象。如果 T 是类类型的类或数组,则它必须具有可访问且不可删除的析构函数。

在这种情况下,对 constructor 的额外调用将​​变为 move 操作。在 C++17 之前,复制省略不是强制性的,编译器通常会复制省略。据我所知,在您的情况下,编译器无论如何都会复制 elide(尝试 godbolt 并检查生成的程序集)。

要完整回答,一调用构造函数,一招。

【讨论】:

    猜你喜欢
    • 2011-10-30
    • 1970-01-01
    • 2023-03-12
    • 2014-09-05
    • 2017-01-27
    • 2011-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多