函数返回值上未调用拷贝构造函数

6

GCC会内联语句——不管我怎样试图阻止它。我尝试了:

  • -fno-inline
  • -O0
  • __attribute__ ((noinline))
  • dummy asm("")

但是都没有成功!以下是代码:

#include<iostream>

using namespace std;

struct A {
  A() {cout << "A::A()" <<endl; }
  A(const A& a) {cout << "A::A(copy)" <<endl; }
  A& operator=(const A& a) {cout << "A::=()" <<endl; return *this;}
};

A __attribute__ ((noinline)) func() 
{
  cout << "func()" << endl;
  A loc;
  asm("");
  return loc;
}

int main() {
  A a = func();
}

这个(g++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2)的不幸结果是

func()
A::A()

语句 A a = func(); 发生了什么?

进行这个实验的原因是我想知道当执行到这条语句时会发生什么(因为我需要控制它的执行方式):

A a = func();

我看到在进行以下操作时会调用复制构造函数:

A a = b;

在这种情况下,调用的是复制构造函数。但在A a = func();的情况下不会调用,而是进行内联操作。我需要控制这个语句,因为我的“struct A”在实际应用中包含需要处理的动态分配数据。
我是否漏掉了什么显而易见的东西?!

2
尝试使用“-fno-elide-constructors”选项。(请注意,通过在类定义内部定义构造函数,您已经将它们声明为内联。) - Kerrek SB
1
这真的是内联吗?在我看来更像是RVO。 - Amardeep AC9MF
当您需要在该点调用复制构造函数时,您的类已经出现问题了。任何具有适当构造函数/析构函数/复制构造函数/赋值运算符的足够明智的类都可以通过进行RVO而正常工作。 - PlasmaHH
@PlasmaHH 这不是矛盾吗?你说过有正确设置的构造函数/析构函数/复制构造函数/赋值运算符,那么此时我就不需要复制构造函数了?!? - ritter
1
@David:这并不意味着它是“内联的”(就像-fno-inline影响的那样)。内联成员函数与ODR有关,而不是机器代码生成。 - R. Martinho Fernandes
显示剩余10条评论
3个回答

18

不,这与函数被内联没有任何关系。将函数内联不会改变可观察的行为。

这是一种称为复制省略的优化,它允许编译器通过直接在目标处构造返回值来避免复制。您可以使用g++标志-fno-elide-constructors禁用它。

无论如何,动态分配的数据都不应该是问题。假设有一个合理的复制构造函数,您可能会看到的唯一区别可能是更好的性能。


6
如果 struct A 包含动态分配的数据,则需要在适当的析构函数/构造函数中管理该内存。许多类管理动态分配的数据,并且使用省略复制也可以正常工作。RVO和NRVO是重要的优化。

3

如果有人(像我一样)真的想避免使用inline

-fkeep-inline-functions -fno-inline

-fkeep-inline-functions
即使所有对给定函数的调用都被集成,并且该函数被声明为静态的,仍然输出一个单独的可运行版本的函数。此选项不影响外部内联函数。

-fno-inline
不理会内联关键字。通常情况下,此选项用于防止编译器将任何函数内联扩展。请注意,如果您没有进行优化,则无法将任何函数内联扩展。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接