6

GCC inlines a statement -- no matter how hard I try to prevent it. I tried

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

No success! Here the code:

#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();
}

The unfortunate output of this (g++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2) is

func()
A::A()

What happened to the statement A a = func(); ??

The reason for this experiment is that I would like to know what happens when execution comes to this statement (because I need control how this is done):

A a = func();

I read that the copy constructor is called when one does

A a = b;

(In this case the copy-constructor is called. But not in the case A a = func();) The function is inlined instead. I NEED control over this statement since my "struct A" in real life contains dynamically allocated data that needs to be taken care of.

Am I missing something obvious here ?!

Pharap
  • 3,826
  • 5
  • 37
  • 51
ritter
  • 7,447
  • 7
  • 51
  • 84
  • 2
    Try `-fno-elide-constructors`. (And note that you did declare your constructors inline by virtue of defining them inside the class definition.) – Kerrek SB Aug 30 '11 at 13:57
  • 1
    Is that really inlining? It looks like RVO to me. – Amardeep AC9MF Aug 30 '11 at 14:00
  • Thanks for the answer! Indeed, it is not inlining. It is optimization. With this I will see if get my real life struct to work. (At the moment it does not). One question: Can turning off this optimization possibility (-fno-elide-constructors) change the program behaviour (say if the copy constructor contains vital code) except for speed? – ritter Aug 30 '11 at 14:13
  • When you need the copy ctor called at that point, your class is broken. Any sufficiently sane class with proper ctor/dtor/copyctpr/op= will just work fine with RVO taking place. – PlasmaHH Aug 30 '11 at 14:13
  • Well, obviously it can. It prevented the output "A::A(copy)" from the copy constructor. Eh.. That might mean, that i need to turn it off to get a working program? (in case I need the copy constructor..) – ritter Aug 30 '11 at 14:15
  • @PlasmaHH Isn't that contradictory? You said with properly set up ctor/dtor/copyctpr/op= I shouldn't need a copyctpr at that point ?!? – ritter Aug 30 '11 at 14:18
  • @Frank: No, with all those functions properly written, it does not matter whether the copy at that point is elided or not. What exactly makes you think you need that copy ctor call? What do you think will go wrong when it is not done? – PlasmaHH Aug 30 '11 at 14:21
  • @Frank: Yes, it is inlining. 9.3 (Member functions) para 2: "*A member function may be defined in its class definition, in which case it is an inline member function ...* – David Hammen Aug 30 '11 at 14:22
  • 1
    @David: that doesn't mean it's "inlined" (as in what `-fno-inline` affects). An *inline member function* has to do with the ODR, not machine code generation. – R. Martinho Fernandes Aug 30 '11 at 14:27
  • @PlasmaHH I have strong feelings that I need the copy ctor call in this case. A new question is a better suited place... – ritter Aug 30 '11 at 14:39
  • @Martinho: 9.3.2 explicitly refers to 7.1.2 to say what “inline member function” means, and 7.1.2 says, “The inline specifier indicates to the implementation that inline substitution of the function body at the point of the call is to be preferred to the usual function call mechanism.” Sounds tightly connected to `-fno-inline` to me. – Christopher Creutzig Aug 30 '11 at 14:43
  • @PlasmaHH I think i get it. In other words: A class is wrong written if the copy-ctor executes some functionality that is not executed by any of the other constructors, e.g. for RVO. – ritter Aug 30 '11 at 14:55
  • @Kerrek SB You were the first first to point to elided copy-ctors. I think you deserve the correct answer state. Could you post one? – ritter Aug 30 '11 at 14:57
  • @Frank: Thanks, that's very kind of you, but don't worry - no point repeating what's been said, do feel free to accept another answer! – Kerrek SB Aug 30 '11 at 15:03
  • Possible duplicate of [Copy constructor not being called](https://stackoverflow.com/questions/3977893/copy-constructor-not-being-called) – Pharap Apr 18 '19 at 18:46

3 Answers3

18

No, this has nothing to do with the function being inlined. Inlining the function would not change observable behaviour.

This is an optimization called copy elision that allows the compiler to avoid a copy by constructing the return value directly at the destination. You can disable it with the g++ flag -fno-elide-constructors.

In any case, the dynamically allocated data should not be a problem. Assuming a sane copy constructor, the only difference you will see will be possibly better performance.

Matthew Hoggan
  • 7,402
  • 16
  • 75
  • 140
R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
6

If struct A contains dynamically allocated data, then it's your responsibility to manage that memory in the appropriate destructor/constructor. Many classes manage dynamically allocated data and work just fine with ellided copies. RVO and NRVO are important optimizations.

Puppy
  • 144,682
  • 38
  • 256
  • 465
3

In case anyone (like me) is really looking for avoiding inline:

-fkeep-inline-functions -fno-inline

-fkeep-inline-functions
Even if all calls to a given function are integrated, and the function is declared static, nevertheless output a separate run-time callable version of the function. This switch does not affect extern inline functions.

-fno-inline
Don't pay attention to the inline keyword. Normally this option is used to keep the compiler from expanding any functions inline. Note that if you are not optimizing, no functions can be expanded inline.

Community
  • 1
  • 1
Adrian Maire
  • 14,354
  • 9
  • 45
  • 85