Thread: CConstructor Infinite Recursion!

  1. #1
    The Dragon Reborn
    Join Date
    Nov 2009
    Location
    Dublin, Ireland
    Posts
    629

    CConstructor Infinite Recursion!

    Hi all!,
    so I have finally reached the stage where I am "forced" to learn about Copy constructor. And i understand the basics of it.
    When we pass an object by value as parameter, the Copy Constructor is called.
    What I don't get is...how does it lead to an infinite recursion? Whereas pass by reference
    doesn't ?


    Code:
               class Dog
               {
                        
                    Dog(){}
    
                    Dog(const Dog &dog)
                  {
                           //safe
                  }
              
                  Dog(Dog dog) 
                  {
                          height=dog.height; //...
    
                          //leads to infinite recursion. But I don't see how!
                  }
    
               }
    how does the pass by copy lead to an infinite recursion ?

    The copy constructor copies the all the member variables, does it copy the function code as well? , it copies them and pushes it onto the stack and it should stop.
    Why would the copy constructor need to be called again, and again?
    Can you please explain this to a noob.
    Thanks.

  2. #2
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Because when you have
    Code:
    Dog(Dog dog)
    you are passing a Dog, by copy, to the copy constructor. So the copy constructor must call itself to make a copy of the passed-in Dog; this constructor is passed a Dog, by copy, so it must call itself to make a copy of the passed-in Dog; ....

  3. #3
    The Dragon Reborn
    Join Date
    Nov 2009
    Location
    Dublin, Ireland
    Posts
    629
    Quote Originally Posted by tabstop View Post
    Because when you have
    Code:
    Dog(Dog dog)
    you are passing a Dog, by copy, to the copy constructor. So the copy constructor must call itself to make a copy of the passed-in Dog; this constructor is passed a Dog, by copy, so it must call itself to make a copy of the passed-in Dog; ....
    i'm sorry but that still doesn't make sense to me.

    this is the explanation i have been seeing on many forums and I don't get it.
    Why does it copy itself ?
    The copy constructor already copied a dog object. so therefore why can't it just end after its copy? and then execute the rest of the code? why call it self again?

  4. #4
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by Eman View Post
    The copy constructor already copied a dog object.
    Whoa whoa whoa whoa whoa. HOW did the copy constructor "already copied" anything? The only way to copy anything is ... the copy constructor. If the first thing in your copy constructor is "copy another dog object", then you're never going to get started.

  5. #5
    The Dragon Reborn
    Join Date
    Nov 2009
    Location
    Dublin, Ireland
    Posts
    629
    Quote Originally Posted by tabstop View Post
    Whoa whoa whoa whoa whoa. HOW did the copy constructor "already copied" anything? The only way to copy anything is ... the copy constructor. If the first thing in your copy constructor is "copy another dog object", then you're never going to get started.
    ha, now you are confusing me.
    what i mean is when the copy constructor is called.
    it should do this :
    Code:
                Dog(Dog dog) //At this stage it would have a copy of the dog object
               {
                         //so it should execute this code
                      weight = dog.weight//and so on..
                   //then end instead of calling this constructor again 
               }

  6. #6
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by Eman View Post
    [CODE]
    Dog(Dog dog) //At this stage it would have a copy of the dog object
    Whoa whoa whoa whoa whoa! How can it have a copy of the dog object? This is what the copy constructor is for! You can't even get past this line of the copy constructor without calling another copy constructor (actually, the same copy constructor, which is the problem).

  7. #7
    The Dragon Reborn
    Join Date
    Nov 2009
    Location
    Dublin, Ireland
    Posts
    629
    Quote Originally Posted by tabstop View Post
    Whoa whoa whoa whoa whoa! How can it have a copy of the dog object? This is what the copy constructor is for! You can't even get past this line of the copy constructor without calling another copy constructor (actually, the same copy constructor, which is the problem).
    em ok so. I am trying to break it down. I need to "see" how it <b>calls</b> itself again
    Code:
              Dog(Dog dog) 
    
               yes I see what you mean that the copy constructor would still have to copy the existing dog object. to the new object. 
    
           so 
           
             Dog(Dog dog)
           {
                 weight = dog.weight
                 //this line of code should execute.//then it should quit!
                //how does it perform a recursive call? or does the above line of code even                     
               //execute? Pardon my slowness
    
               }

  8. #8
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    But it won't get to that.

    If I'm the compiler and I see

    Dog fido(rex);

    and it's calling

    Dog(Dog dog)

    well I need to make a local copy of rex for the function to use, so I call the copy constructor again, I need to make a local copy of rex for the function to use, so I call the copy constructor again, I need to make a local copy of rex for the function to use, so I call the copy constructor again, I need to make a local copy of rex for the function to use, so I call the copy constructor again ... seems like a problem!

    When you want to fully understand a call to a function, you should move in top-down order; if the computer is supposed to copy the argument, that will happen first. You need to stop thinking about what happens later in order to see the recursion.

  9. #9
    The Dragon Reborn
    Join Date
    Nov 2009
    Location
    Dublin, Ireland
    Posts
    629
    Quote Originally Posted by whiteflags View Post
    But it won't get to that.

    well I need to make a local copy of rex for the function to use, so I call the copy constructor again, I need to make a local copy of rex for the function to use, so I call the copy constructor again, I need to make a local copy of rex for the function to use, so I call the copy constructor again, I need to make a local copy of rex for the function to use, so I call the copy constructor again ... seems like a problem!
    hello wflags.
    yep, I know it causes a recursion if I pass the object by value instead of passing the reference. You are giving me the same answer tabstops did and every other forum page has.
    But they neglect to explain <b>why</b> it is happening.
    yes, when you do this
    void fido(rex)
    the compiler needs to make a local copy of rex for the fido function to use. So it calls a copy constructor to copy the members to the new rex object (the copied object)
    so this copy constructor is called, the one we've defined(the one we "know" to be wrong)
    Code:
               Dog(Dog a )
             {
                   dog = a.weight ;
    
                }
    fine it has called the copy constructor, how does the C ctor call itself again? The compiler has made a local copy once, why would it need to make another copy again.

    I feel like I am going nowhere

  10. #10
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Eman
    fine it has called the copy constructor, how does the C ctor call itself again?
    I was going to give you an example to demonstrate that the recursion happens before control enters the body of the constructor, but I cannot: I have not checked the C++ standard, but the Comeau online compiler, the MinGW port of g++ 3.4.5 and MSVC10 all reject my sample program. If they are correct, there is no infinite recursion because all along you've been talking about a program that is invalid C++.

    Quote Originally Posted by Eman
    The compiler has made a local copy once, why would it need to make another copy again.
    If it were valid C++, then it would need to make another copy again because you told it to. Basically, the idea is that the parameter indicates that the argument is to be copied. However, this very function is the one that does that copying. Therefore, in theory, invoking this constructor involves invoking this constructor to copy the object before control enters the body of the constructor. That second invocation in turn invokes the same constructor to copy the object before control enters the body of the constructor, and this third invocation invokes the same constructor...

    To use your sample code:
    Code:
    Dog(Dog dog)
    {
        weight = dog.weight
        //this line of code should execute.//then it should quit!
        //how does it perform a recursive call? or does the above line of code even                     
        //execute? Pardon my slowness
    }
    The comment that says "this line of code should execute" is hopeful, but in vain. The line (or rather, the line with the assignment before it) is actually unreachable, were this code snippet valid C++, which it is not.
    Last edited by laserlight; 12-21-2010 at 09:08 AM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  11. #11
    The Dragon Reborn
    Join Date
    Nov 2009
    Location
    Dublin, Ireland
    Posts
    629
    I was hoping you and Elysia would come online
    Yeah, my compiler wouldn't let me do that but I will sleep better if I understand what was going on. Which i still don't :'(

    Quote Originally Posted by laserlight View Post
    Therefore, in theory, invoking this constructor involves invoking this constructor to copy the object before control enters the body of the constructor.
    I don't get what you mean.
    when you do this
    Code:
          Dog a ;
    
          a = b//...this invokes the copy constructor - the function that will copy the                  
                  //object.
    Am i correct that you are saying that at this point

    Dog(Dog a)
    that
    Another copy constructor-the same copy constructor- is being called to copy the dog object? if i am,then i want know what is invoking the copy constructor again?
    Is it this statement
    Dog a

    or this statement

    Dog()

  12. #12
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Eman
    Dog(Dog a)
    that
    Another copy constructor-the same copy constructor- is being called to copy the dog object? if i am,then i want know what is invoking the copy constructor again?
    Is it this statement
    Dog a

    or this statement

    Dog()
    It is by virtue of the parameter being of type Dog. Try this program:
    Code:
    #include <iostream>
    #include <cstdlib>
    
    class Dog;
    
    void foo(Dog dog);
    
    class Dog
    {
    public:
        Dog() {}
    
        Dog(const Dog& other)
        {
            std::cout << "Dog copy ctor" << std::endl;
            foo(other);
        }
    };
    
    void foo(Dog dog)
    {
        std::cout << "foo" << std::endl;
        std::exit(0);
    }
    
    int main()
    {
        Dog main_dog;
        foo(main_dog);
    }
    Observe that foo exits from the program yet there is the infinite loop. You can conclude that the std::exit(0); and in fact the whole body of the foo function, is unreachable. It is unreachable because its parameter is of type Dog, causing the copy constructor to be invoked. But the copy constructor prints a message then invokes foo, which in turn causes the copy constructor to be invoked...

    So, if what you were trying to do were legal, we would be bypassing this additional foo function and just combining it into a single constructor. The effects would be the same.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  13. #13
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    It is the argument itself that would be a problem. You're confusion is a perfect example of why such code makes no sense. You're implementing the copy constructor in pass-by-value semantics, which in theory implements the constructor in terms of itself. IOW, you're implementing a copy constructor that relies on another copy constructor for the exact same class, which is dubious.

    So by design a copy constructor can only be something like

    foo(const foo &rhs);

    The types would not be different, unless C++ didn't use references anymore. If that were the case, well, I wonder if we really would depend on another pass-by-reference type, like the humble pointer.

  14. #14
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by whiteflags
    So by design a copy constructor can only be something like

    foo(const foo &rhs);
    Yeah, though it can also be:
    Code:
    foo(foo& rhs);
    and some other variants involving volatile and additional parameters with default arguments, but I have only ever written (and seen in practice) the const reference version.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  15. #15
    The Dragon Reborn
    Join Date
    Nov 2009
    Location
    Dublin, Ireland
    Posts
    629
    Quote Originally Posted by laserlight View Post
    It is by virtue of the parameter being of type Dog. Try this program:
    Code:
    #include <iostream>
    #include <cstdlib>
    
    class Dog;
    
    void foo(Dog dog);
    
    class Dog
    {
    public:
        Dog() {}
    
        Dog(const Dog& other)
        {
            std::cout << "Dog copy ctor" << std::endl;
            foo(other);
        }
    };
    
    void foo(Dog dog)
    {
        std::cout << "foo" << std::endl;
        std::exit(0);
    }
    
    int main()
    {
        Dog main_dog;
        foo(main_dog);
    }
    Observe that foo exits from the program yet there is the infinite loop. You can conclude that the std::exit(0); and in fact the whole body of the foo function, is unreachable. It is unreachable because its parameter is of type Dog, causing the copy constructor to be invoked. But the copy constructor prints a message then invokes foo, which in turn causes the copy constructor to be invoked...

    So, if what you were trying to do were legal, we would be bypassing this additional foo function and just combining it into a single constructor. The effects would be the same.
    Wow yeah your code makes sense.

    so
    foo(main_dog) //main_dog invokes the copy constructor, which after executing the cout statements, calls the function again, thereby a recursive call.
    Although in this case you are inducing the recursion.

    Are you saying this is what happens ?

    When i did

    Dog a( b) // b is an existing object

    are you saying that the instance "Dog a(b)" is always invoked by the constructor?

    Why is that happening?
    I mean in your code it is clear why it is happening, but in the copy constructor we wrote.
    We passed by value, yes, we do not however call the instance again...

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Template Recursion Pickle
    By SevenThunders in forum C++ Programming
    Replies: 20
    Last Post: 02-05-2009, 09:45 PM
  2. convert Recursion to linear can it be done
    By umen242 in forum C++ Programming
    Replies: 2
    Last Post: 10-15-2008, 02:58 AM
  3. Recursion... why?
    By swgh in forum C++ Programming
    Replies: 4
    Last Post: 06-09-2008, 09:37 AM
  4. Recursion
    By Lionmane in forum C Programming
    Replies: 11
    Last Post: 06-04-2005, 12:00 AM
  5. a simple recursion question
    By tetra in forum C++ Programming
    Replies: 6
    Last Post: 10-27-2002, 10:56 AM