1

I was preparing lecture on copy constructor and found this:

MyClass myFunction()
{
   MyClass mc;
   return mc;
}

the statement says:

If we call myFunction, then C++ will create a new myClass object that's initialized to mc when myFunction returns. Thus while your code might act like it's transparently moving the object from inside of myFunction to the rest of your code, it's actually making a temporary copy.

I think statement MyClass mc; will create the object and it returned form function not any temporary object. Where am I going wrong? Can somebody elaborate the statement to be able to understand easily?

Quentin
  • 62,093
  • 7
  • 131
  • 191
Abhijatya Singh
  • 642
  • 6
  • 23
  • 8
    NRVO (Named Return Value Optimization) elides that copy constructor (when applied). – Jarod42 Jun 09 '16 at 14:44
  • https://stackoverflow.com/questions/12953127/what-are-copy-elision-and-return-value-optimization – Cory Kramer Jun 09 '16 at 14:46
  • And move constructors (when available) does exactly the move. I think, the lecture is terribly outdated and not clear at all. – SergeyA Jun 09 '16 at 14:47

2 Answers2

3

I think statement MyClass mc; will create the object

Correct.

and it returned form function not any temporary object.

I don't fully understand your statement, so I cannot tell whether you've gone wrong, but this is what happens:

mc is a local variable. Local variables are destroyed when the function exits. Before it is destroyed, a temporary object is copy-initialized from it. The temporary object is then returned from the function.

Extra knowledge 1: Since C++11, the temporary is copy-initialized by move, if possible.

Extra knowledge 2: Standard explicitly allows the compiler to skip the copy/move and instead construct the object at the call site. This optimization is known as (named) return value optimization and is a form of copy elision. Despite this, you can not return objects that are neither copyable nor movable. That is because an implementation of C++ is not required to do NRVO.

Ajay
  • 18,086
  • 12
  • 59
  • 105
eerorika
  • 232,697
  • 12
  • 197
  • 326
  • Your answer seems self-contradictory. "X happens". "X is allowed not to happen". – juanchopanza Jun 09 '16 at 15:08
  • @juanchopanza I avoid mentioning the exception on purpose for easier explanation of the statement that OP is asking about. Understanding copy elision is not necessary to understand returning by value. But knowing about copy elision before you understand returning by value can easily lead to misunderstanding. – eerorika Jun 09 '16 at 15:13
1

Let's say you have this code:

#include <iostream>
using namespace std;

class MyClass
{
public:

    int *v;

    MyClass()
    {
        v=new int[5];
        for(int i=0;i<5;i++) v[i]=i;  // x will look like : 0,1,2,3,4
    }

    ~MyClass()
    {
        cout<<"Destructor called! Now v is deallocated! \n";
        delete[] v;
    }
};

MyClass myFunction()
{
   MyClass mc;
   return mc;
}

int main()
{
    MyClass x;

    x=myFunction();

    cout<<x.v[2]<<'\n'; //it may or may not print the right thing

    return 0;
}

As you can see, myFunction returns the object mc like you said. But you also know that the destructor of mc will be called when mc goes out of scope - mc is declared inside myFunction, so the destructor will be called after the function is executed and memory will be freed (delete[] v). The memory is deallocated, but the values are still there in the memory! So, even though x=myFunction(); will work, you will have an object where the memory v points to is deallocated! So, cout<<x.v[2]<<'\n'; may not print the right thing. If you compile the code it will probably print the correct value (2), because the memory was not overwritten, but if you would do some more allocations before the cout statement, or after some time of using your OS, you will see that the value printed is incorrect/crash as the memory will be overwritten by other programs. v still points to that memory block, but it doesn't know what's there because the memory is deallocated.

Inside myFunction: v -> |0|1| 2 |3|4|...

After exiting myFunction: v -> |0|1| 2 |3|4|.....

After some memory allocations: v -> |a|1| b |@|%|3|7|2|1|*|!|......

Toma Radu-Petrescu
  • 2,152
  • 2
  • 23
  • 57
  • Sir two doubts: after function call the memory is deallocated by destructor. so x has a pointer which points to garbage. The cout statement should ideally give error memory corruption if not then after x goes out of scope destructor is called again then it gives. Second is where is temporary object concept applied here. – Abhijatya Singh Jun 09 '16 at 18:10
  • Sir I have executed the code above on linux and g++ compiler it prints cout correctly after that it gives memory error. I would like to know why it is printing first time correctly while theoretically the memory is deallocated by delete operator. – Abhijatya Singh Jun 09 '16 at 18:15
  • I don't really know the answer but I assume that it has to do with the way the operating system manages the memory. On Windows, GCC, for example, I can even execute cout< – Toma Radu-Petrescu Jun 09 '16 at 18:22