6
class test{

public:

    int data;
    test(const test& ){cout<<"INSIDE COPY CON "<<endl;}
    test(int val = 0) : data(val){ cout<<"INSIDE CON "<<endl; }

    test testfun(const test& obj)
    {
        cout<<"data : "<<data<<endl;
        //test test3(this->data + obj.data);
        //cout<<"test3 :"<<test3.data<<endl;
        //return test3;   //This will work only if return type is changed to const ref
        return test(data + obj.data); 


    }
};

int main()
{

    test testO1(1);
    test testO2(2);
    test testO3 = testO1.testfun(testO2);

    cout<<testO3.data<<endl;


    getchar();


}

OUTPUT:

INSIDE CON

INSIDE CON

data : 1

INSIDE CON

3

What happens when constructor is called in return statement? Since i am able to return by value and it works i think its not a temporary location. OR is it creating the object as a temporary and using copy constructor to copy the values , inthat case why is the print inside the copy constructor not getting printed.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
hackrock
  • 317
  • 1
  • 4
  • 13
  • More on [NRVO](http://definedbehavior.blogspot.com/2011/08/value-semantics-nrvo.html) and [copy elision](http://definedbehavior.blogspot.com/2011/08/value-semantics-copy-elision.html) in general. – David Rodríguez - dribeas Jun 08 '12 at 03:42

3 Answers3

10

It creates a temporary object, which then gets copied to the return value.

But for efficiency, C++ allows calls to the copy constructor (or the move constructor in C++11) to be elided, so you should not rely on side-effects of copy constructors occurring.

See Return Value Optimization and Want Speed? Pass By Value

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
  • But what if i dont want shallow copy to happen, like if there is some pointer initialization and i want defined copy constructor to be called? – hackrock Jun 08 '12 at 00:48
  • 2
    @rocky: The RVO means that instead of copying, the object essentially gets constructed in the memory space of the callee variable (`testO3` in your case). Why would you *need* to have the copy constructor called? – Oliver Charlesworth Jun 08 '12 at 00:52
7

You ask a penetrating question.

It is up to the compiler and the associated toolchain to decide what to do, but the basic pattern is as follows. Before calling testfun(), the caller [main(), in your example] reserves space for test03 on the stack. It then passes the address of test03 to testfun().

The function testfun() must somehow put a test object at the address the caller has supplied. If the function has only one return statement, it is free to use the storage provided by the caller to build the return value. It need not use its own storage. It can use main()'s.

Now, this strategy does not always work. It typically fails when a function like testfun() has two, distinct return statements, one or both of which return not a temporary but a named object. In that case, the compiler is forced to do an otherwise unnecessary copy-on-return. However, the more usual case resembles yours, in which testfun() just builds the return value directly in the spot in which main() wants it. In this case, no actual copy occurs.

It is thus up to the compiler to decide whether the copy constructor is called on return in a case like this.

thb
  • 13,796
  • 3
  • 40
  • 68
  • Only on return statements. However, no default bit copy occurs in either case. The two choices are (a) a deep copy and (b) no copy at all. How is (b), no copy at all, possible? Because the called function *originally* uses the caller's memory to construct the object. In case (b), the caller never has its own, local object at all. If you are getting (c) an actual bit-copy, this is behavior I admit that I have never seen. – thb Jun 08 '12 at 00:58
  • I was getting confused because when i made the copy constructor private i was getting compiler error. But i found the reason for that in the this link http://stackoverflow.com/questions/4733448/why-copy-constructor-is-called-when-passing-temp-by-const-ref – hackrock Jun 08 '12 at 01:17
0

I tell you what happening when return a constructor, lets make a good example for you. I refer a class named Counter returning in two ways :

return by temporary object :

// method 1
class Counter
{
private :
    int count;
public :
    Counter() : count(0) {}
    int get_count(void);
    Counter operator++(int);
};

int Counter::get_count()
{
    return count;
}

Counter Counter::operator++(int)
{
    count++;
    // create a temp object and assigning count value, then return.
    Counter temp;
    temp.count = count;
    return temp;
}

return by nameless temporary object:

// method 2
class Counter
{
private :
    int count;
public :
    Counter() : count(0) {}
    Counter(int c) : count(c) {}
    int get_count(void);
    Counter operator++(int);
};

int Counter::get_count()
{
    return count;
}

Counter Counter::operator++(int)
{
    count++;
    // call 'Counter(int c)' constructor
    return Counter(count);
}

main :

#include <iostream>
using namespace std;

int main()
{
    Counter c1, c2;
    c1++;
    c1++;
    c2 = c1++;
    cout << "c1=" << c1.get_count() << endl;
    cout << "c2=" << c2.get_count() << endl;
    return 0;
}

The output of both methods are identical, the return Counter(count); statement in second class does what all three statements did in the first. this statement creates an object of type Counter, this object has no name; it wont be around long enough to need one. this unnamed object is initialized to the value provided by the argument count, once the unnamed object is initialized to the value of count, it can then be returned.

The effect of the first class are the same as the second class :

Output :

c1= 3
c2= 3

notice, in c2 = c1++; statement c1 increased then assigned to c2.