Copy constructor

This is a discussion on Copy constructor within the C++ Programming forums, part of the General Programming Boards category; why is it in function test2 the copy constructor is called twice ? Code: #include <cstdlib> #include <iostream> using namespace ...

  1. #1
    Registered User
    Join Date
    Nov 2005
    Posts
    95

    Copy constructor

    why is it in function test2 the copy constructor is called twice ?

    Code:
    #include <cstdlib>
    #include <iostream>
    
    using namespace std;
    
    
    class strings 
       {
       char   str[256];
    public : 
       strings(const char *s)
          {
          strcpy(str, s);
          }
       strings(const strings &s)
          {
          cout << "copy constructor  = " << s.str << endl;
          strcpy(str, s.str);
          }
        ~strings(void)
          {
          cout << "Destructing string   " << str << endl;
          }
       void test1(const strings Obj1)
          {
          cout << "in test1 " << Obj1.str << endl;
          }
       strings test2(const strings Obj2)
          {
          cout << "in test2 " << Obj2.str << endl;
          return(Obj2);
          }
    };
    
        
    int main(int argc, char *argv[])
    {
    strings  s1("Hellow world");
    
    cout << "Calling test1 : " << endl; 
    s1.test1(s1);
    cout << "\n\nCalling test2" << endl; 
    s1.test2(s1);
    
    system("PAUSE");
    return EXIT_SUCCESS;
    }
    Begin the ouput :
    Calling test1 :
    copy constructor = Hellow world
    in test1 Hellow world
    Destructing string Hellow world


    Calling test2
    copy constructor = Hellow world
    in test2 Hellow world
    copy constructor = Hellow world
    Destructing string Hellow world
    Destructing string Hellow world
    Press any key to continue . . .
    End output.

    The part in blue I understand. this is from assinging s1 to obj2.
    But where does the part in orange comes from ?

  2. #2
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,794
    The part in orange comes when the test2 function must return an object of type strings. To do this, it returns Obj2 which gets "copied" as the return parameter (which goes nowhere). This is also why the destructor gets called twice there at the end. First the copy we just made gets destructed, and then s1 itself gets destructed.
    "Owners of dogs will have noticed that, if you provide them with food and water and shelter and affection, they will think you are god. Whereas owners of cats are compelled to realize that, if you provide them with food and water and shelter and affection, they draw the conclusion that they are gods."
    -Christopher Hitchens

  3. #3
    Registered User
    Join Date
    Nov 2005
    Posts
    95

    Sorry ?

    But can't the desructing of s1 !!

    Quote Originally Posted by hk_mp5kpdw
    First the copy we just made gets destructed, and then s1 itself gets destructed.
    Code:
    #include <cstdlib>
    #include <iostream>
    
    using namespace std;
    
    class test
       {
    public:
       int  i;
       ~test(void)
          {
          cout << "Destructing " << i << endl;
          }
    };
    
    void fun(void)
    {
    test  tf;
    tf.i = 10;
    }
    
    
    int main(int argc, char *argv[])
    {
    test  t1;
    t1.i = 20;
    
    fun();
    
    system("PAUSE");
    return EXIT_SUCCESS;
    }
    The output:
    Destructing 10
    Press any key to continue . . .
    End output.

    We don't see the desruction of t1 because it is done after main is finished.

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    21,453
    Um, what is your question now?
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    Registered User
    Join Date
    Nov 2005
    Posts
    95

    The same one

    At the beging of this thread I wrote a program with two functions
    test1() and test(). and the output was :

    >> Begin the ouput :Calling test1 :
    copy constructor = Hellow world
    in test1 Hellow world
    Destructing string Hellow world


    Calling test2
    copy constructor = Hellow world
    in test2 Hellow world
    copy constructor = Hellow world
    Destructing string Hellow world
    Destructing string Hellow world
    Press any key to continue . . .
    >> End output.

    The part in blue I understand. this is from destrucating Obj2
    But what am I destructing in the orange line ?

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    21,453
    Calling test2
    At this point control is in the main() function, and s1.test2(s1) is about to be called.

    copy constructor = Hellow world
    Control has just been passed to the member function test2(). Obj2 is constructed as a copy of s1 from the main() function.

    in test2 Hellow world
    copy constructor = Hellow world
    Okay, so the message was printed... and we have another copy constructor call. We can deduce that this call is made from the return statement.

    Destructing string Hellow world
    Since constructors and destructors are paired in a stack-like way, this destructor call is from the return statement. If there was an object to copy to in main(), then this destructor call would not even be there.

    You could alter the line to:
    Code:
    strings s2 = s1.test2(s1);
    to see if one of the destructors is no longer called until main() returns.

    Destructing string Hellow world
    This is the destructor call for Obj2
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    Registered User
    Join Date
    Nov 2005
    Posts
    95

    Thanks

    Quote Originally Posted by laserlight
    Okay, so the message was printed... and we have another copy constructor call. We can deduce that this call is made from the return statement.
    Well , I don't like much the part of "We can deduce". But guess I will have to live with it.

    Quote Originally Posted by laserlight
    You could alter the line to:
    Code:
    strings s2 = s1.test2(s1);
    to see if one of the destructors is no longer called until main() returns.
    I tried it and you are Right. I got only one line of
    "Destructing string Hellow world".


    Thank you.

  8. #8
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,893
    The deduction is ... unreliable, let's put it this way. It's actually more likely that the function parameter is destructed first. It may be guaranteed.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    21,453
    It's actually more likely that the function parameter is destructed first. It may be guaranteed.
    I dont think so, since the argument passed only goes out of scope after the object to be returned is constructed, so the object to be returned should be destroyed first if it isnt passed to some object in the caller.
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  10. #10
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,893
    Easy enough to test.
    Code:
    #include <iostream>
    using std::cout;
    using std::endl;
    
    class Test
    {
    	static int counter;
    
    	int id;
    public:
    	Test()
    		: id(++counter)
    	{
    		cout << "Object #" << id << " default-constructed." << endl;
    	}
    
    	Test(const Test &rhs)
    		: id(++counter)
    	{
    		cout << "Object #" << id << " copy-constructed from #" << rhs.id
    			<< "." << endl;
    	}
    
    	~Test()
    	{
    		cout << "Object #" << id << " destructed." << endl;
    		// Don't decrement counter to avoid confusion.
    	}
    };
    
    int Test::counter = 0;
    
    Test func(Test param)
    {
    	return param;
    }
    
    int main()
    {
    	Test test;
    	func(test);
    	Test test2 = func(test);
    }
    Code:
    Object #1 default-constructed.
    Object #2 copy-constructed from #1.
    Object #3 copy-constructed from #2.
    Object #3 destructed.
    Object #2 destructed.
    Object #4 copy-constructed from #1.
    Object #5 copy-constructed from #4.
    Object #4 destructed.
    Object #5 destructed.
    Object #1 destructed.
    Seems that at least for GCC, you're right.

    It still surprises me a bit.

    Edit: OK, I think I know where my mistake was. I assumed it was the callee's responsibility to destruct parameters.
    Last edited by CornedBee; 01-08-2006 at 10:38 AM.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  11. #11
    Registered User
    Join Date
    Nov 2005
    Posts
    95

    What is the red line ?

    [QUOTE=CornedBee]
    Code:
    class Test
    {
    	static int counter;
    
    	int id;
    public:
    	Test()
    		: id(++counter)	{
    		cout << "Object #" << id << " default-constructed." << endl;
    	}
    
    };

    I know what is static variable in class.

    Code:
    class A {
          int  i;
    public:
          A(int Ii)
             {
             i = Ii;
             }
    };
    
    class B : public A
    public :
           B(int Ii) : A(Ii)
              {
              // something.
              }
    };
    Is it something like ":A(Ii)" ? But "id" is a variable.

  12. #12
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    21,453
    CornedBee is just using a constructor initialisation list.
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  13. #13
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,794
    That a part of what's called the initialization list. It's just another way to initialize member variables in a class/struct constructor. It's also the only way to initialize a class/struct's const data members.

    Instead of:

    Code:
    class foo
    {
        int a;
        char b;
        float c;
    public:
        foo()
        {
            a = 10;
            b = 'z';
            c = 8.9f;
        }
    };
    You can do:
    Code:
    class foo
    {
        int a;
        char b;
        float c;
    public:
        foo() : a(10), b('z'), c(8.9f)
        {
        }
    };
    If your class had a const data member, there would be no way to initialize that member in the constructor body because by that time the object is already built and whatever value might be in that const data member is the value its going to have because it can't be changed. The only way to initialize those const data members is to use the initializer list.

    You can't do this:
    Code:
    class foo
    {
        const int a;
    public:
        foo()
        {
            a = 10;  // Won't work, a is const
        }
    };
    You can however do this:
    Code:
    class foo
    {
        const int a; 
    public:
        foo() : a(10) // Ok to do this
        {
        }
    };
    "Owners of dogs will have noticed that, if you provide them with food and water and shelter and affection, they will think you are god. Whereas owners of cats are compelled to realize that, if you provide them with food and water and shelter and affection, they draw the conclusion that they are gods."
    -Christopher Hitchens

  14. #14
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,893
    Same goes for references. You can only initialize references in the initialization list.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  15. #15
    Registered User
    Join Date
    Nov 2005
    Posts
    95

    Thanks all

    Thanks hk_mp5kpdw for the detailed explanation.
    Thanks all.

Page 1 of 2 12 LastLast
Popular pages Recent additions subscribe to a feed

Similar Threads

  1. illegal copy constructor required?
    By ichijoji in forum C++ Programming
    Replies: 1
    Last Post: 03-08-2005, 05:27 PM
  2. Linked list copy constructor issue
    By Craptastic! in forum C++ Programming
    Replies: 1
    Last Post: 08-03-2003, 08:30 PM
  3. copy constructor
    By Eber Kain in forum C++ Programming
    Replies: 1
    Last Post: 09-30-2002, 05:03 PM
  4. Quick ? on copy constructor
    By Traveller in forum C++ Programming
    Replies: 3
    Last Post: 05-03-2002, 10:31 AM
  5. Using strings with the copy constructor
    By Unregistered in forum C++ Programming
    Replies: 3
    Last Post: 08-29-2001, 03:04 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21