Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Copy constructor not being called on function result

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 ?!

like image 698
ritter Avatar asked Aug 30 '11 13:08

ritter


People also ask

Why is my copy constructor not being called?

It's because of copy elision optimization by the compiler. Adding -fno-elide-constructors option to g++ while compiling will disable that optimization.

Under which conditions a copy constructor is called?

A copy constructor is called when a new object is created from an existing object, as a copy of the existing object. The assignment operator is called when an already initialized object is assigned a new value from another existing object.

In what way a copy constructor is automatically invoked?

The copy constructor is invoked when the new object is initialized with the existing object. The object is passed as an argument to the function. It returns the object.

Why copy constructor does not take reference value?

It is necessary to pass object as reference and not by value because if you pass it by value its copy is constructed using the copy constructor. This means the copy constructor would call itself to make copy. This process will go on until the compiler runs out of memory.


2 Answers

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.

like image 73
R. Martinho Fernandes Avatar answered Sep 20 '22 21:09

R. Martinho Fernandes


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.

like image 29
Puppy Avatar answered Sep 17 '22 21:09

Puppy