0

I develop simple c++ class to testing when c++ objects destroy; now I have a problem, when an object return by function, c++ create a new object and return that and when return reference destroy object what is my mistake ?

simple class attached below.

#include <iostream>

using namespace std;

static int freeCounter=0;

class TestCopy {
private:
    string pStr;
public:
    TestCopy(const TestCopy &obj){
        pStr=obj.pStr;
    }
    TestCopy(string &test){
        pStr=test;
    }
    ~TestCopy(){ freeCounter++; cout << freeCounter <<"\t" << pStr << endl; }

    TestCopy get(){
        TestCopy x=*this; 
        return TestCopy(x); // -> TestCopy(x) is first destroy in result
    }

    string getStr(){
        return pStr;
    }
};

int main(){
    string xstr="test";
    TestCopy x(xstr); // x is third destroy
    TestCopy x2=x.get(); // x2 is second destroy

    cout << x.getStr() << endl;

    return 0;
}

and result

1   test
test
2   test
3   test
MohsenTi
  • 361
  • 1
  • 2
  • 17
  • The problem is that none of those `TestCopy`are dynamically allocated, so when the go out of scope they get destroyed. – Rodolfo Dec 15 '15 at 06:43
  • You have to explicitly say that you are returning a reference in the function signature `TestCopy& get(){` notice the '&' that I added – Rodolfo Dec 15 '15 at 06:56
  • 1
    Not quite true, @Rodolfo . Copy elision will take care of the copy construct on return issue and returning a local as a reference is going to blow up in MohsenTi's face because the returned reference isn't going to exist anymore. Moe on copy elision: http://stackoverflow.com/questions/12953127/what-are-copy-elision-and-return-value-optimization – user4581301 Dec 15 '15 at 06:59
  • `return *this;` would have been the simplest, most efficient way. – juanchopanza Dec 15 '15 at 07:28

3 Answers3

1

x in function get is a local object, when the function finishes, x will be destroyed.

so, x is the first destroyed.

seamaner
  • 91
  • 6
0

First a review of OP's code. I've modified it slightly to make what's going on more obvious.

#include <iostream>

using namespace std;

static int allocCounter = 0;

class TestCopy
{
private:
    string pStr;
    int counter;
public:
    TestCopy(const TestCopy &obj)
    {
        allocCounter++;
        counter = allocCounter;
        cout << "copy construct " << counter << endl;
        pStr = obj.pStr;
    }
    TestCopy(const string &test)
    {
        allocCounter++;
        counter = allocCounter;
        cout << "string construct " << counter << endl;
        pStr = test;
    }
    ~TestCopy()
    {
        cout << counter << "\t" << pStr << endl;
    }

    TestCopy get()
    {
        TestCopy x = *this; // copy constructed
        return TestCopy(x); // copy constructed and copy elision
    }

    string getStr()
    {
        return pStr;
    }
    TestCopy & operator=(const TestCopy &obj)
    {
        cout << "assigned " << obj.counter << " to "<< counter << endl;

        pStr = obj.pStr;
//        counter = obj.counter; deliberately left out
        return *this;
    }

};

int main()
{
    string xstr = "test";
    TestCopy x(xstr); // string constructed
    TestCopy x2 = x.get(); // Would be a copy constructed if not for copy elision
    return 0;
}

Output

string construct 1
copy construct 2
copy construct 3
2   test
3   test
1   test

Note no calls to the assignment operator even with TestCopy x=*this;

Alright. Now how do we chop some of this down?

First we get rid of a redundant copy in get

TestCopy get()
{
    return *this; // copy constructed. Or is it? The copy construction could
                  // happen at the caller. Either way it is copied and elided
}

Output

string construct 1
copy construct 2
2   test
1   test

So at this point we know there is no need to copy or assign in get because the return statement will do it for us. This is the important part with respect to OP's question.

But if we change main a bit and add an assignment operator we can observe a bit more interesting behaviour.

int main()
{
    string xstr = "test";
    TestCopy x(xstr); // string constructed
    TestCopy x2(""); //string constructed
    x2 = x.get(); // assigned and a copy construct when returning from get
    cout << "done main" << endl;
    return 0;
}

Output

string construct 1
string construct 2
copy construct 3
assigned 3 to 2
3   test
done main
2   test
1   test

The return from get was assigned to x2, then destroyed. x2 gets destroyed and finally x.

user4581301
  • 33,082
  • 7
  • 33
  • 54
-1

thank you @seaman with your help I found my mistake. by changing

TestCopy x=*this;

with

const TestCopy &x=*this;

problem solved

MohsenTi
  • 361
  • 1
  • 2
  • 17