Thread: Beginner problem with returning objects, my destructor is called and copy destroyed

  1. #1
    Registered User
    Join Date
    Oct 2012
    Posts
    71

    Beginner problem with returning objects, my destructor is called and copy destroyed

    I have a two LongInt objects of class LongInt that I made and one of the methods is to add 2 long ints. For some reason, right before my add method returns the resulting (separate) LongInt object, my destructor gets called and returns wiped out copy!

    I am not sure what is wrong as I am new to C++ (not really new to programming though) and here is the function simplified.

    Code:
    LongInt LongInt::add(const LongInt& otherInt)
    {
    	LongInt result;
    
    
    	/* operations */
    
    
    	return result;
    }
    I ran my function through the debugger and while on return result; I hit step into and the next line goes to the destructor of my class before sending the copy outside of the function. So what gets outside is a blank object.
    Code:
    LongInt result = firstnumber->add(*secondnumber);
    Here is what the outside looks like. Is there something wrong with my compiler or is there just some small mistake I can't find?

  2. #2
    Registered User
    Join Date
    May 2010
    Posts
    4,633
    You need to show more content. There is no way I can see what is wrong with the amount of information you posted. Show the smallest possible complete program that illustrates your problem.

    Jim

  3. #3
    Registered User
    Join Date
    Oct 2012
    Posts
    71
    Not sure how much is needed but here is everything I've written so far.
    Code:
    void main()
    {
    	string number;
    	cout << "Enter the first number\n";
    	cin >> number;
    	LongInt *firstnumber = storenumber(number);
    	cout << "Your number is "; 
    	print_result(*firstnumber);
    	cout<<"and has "<< firstnumber->digits()<<" digits\n";
    	cout<<"Enter the second number\n";
    	cin >> number;
    	LongInt *secondnumber = storenumber(number);
    	LongInt result = firstnumber->add(*secondnumber);
    	print_result(result);
    }
    Code:
    LongInt LongInt::add(const LongInt& otherInt)
    {
    	LongInt result;
    
    
    	ADTList *otherList = otherInt.mlist;
    	ADTList *resultList = result.mlist;
    
    
    	node *myNode = mlist->first_right();
    	node *otherNode = otherList->first_right();
    
    
    	int addition = myNode->value + otherNode->value;
    	int carry = overFlow(addition);
    	
    	resultList->insert_last(addition);
    
    
    	while(!mlist->isFirst(myNode) && !otherList->isFirst(otherNode))
    	{
    		myNode = mlist->next_left(myNode);
    		otherNode = otherList->next_left(otherNode);
    
    
    		addition = myNode->value + otherNode->value + carry;
    		carry = overFlow(addition);
    
    
    		resultList->insert_last(addition);
    	}
    	return result;
    }
    Code:
    class LongInt {public:
    	int sign;
    	ADTList *mlist;
    	LongInt(){mlist = new ADTList();};
    	~LongInt(){delete mlist;};
    	int getsign(){return sign;};
    	void setsign(int i){if(i>0) sign=1; else sign = 0;};
    	LongInt add(const LongInt&);
    	void clear(){delete mlist; mlist = new ADTList();};
    	int digits(){ int i = 0; node *count = mlist->first_right(); if(!count) return 0; else{while(count->prev){count=count->prev;i=i+8;}	int j=count->value;
    	while(j>0){	j=j/10;i++;	}}return i;}
    };
    Code:
    class ADTList
    {
    	public:
    		node *head;
    		ADTList(){head = 0;};
    		~ADTList(){ cout<<"Why is this being called\n"; node *cp = first_right(); while(cp!=0){node *next = cp->next; delete cp; cp=next;}}
    		node *first_right(){ node *cp=head; 
    		if(!cp) return 0; 
    		if(!cp->next) return cp; 
    		while(cp->next) cp=cp->next; 
    		return cp;}
    		node *first_left(){  node *cp=head; if(!cp) return 0; if(!cp->prev) return cp; while(cp->prev) cp=cp->prev; return cp;}
    		node *next_right(node *cp){return cp->next;}
    		node *next_left(node *cp) {return cp->prev;}
    		int isFirst(node *cp){if(cp==first_left()) return 1; else return 0;}
    		int isLast(node *cp) {if(cp==first_right()) return 1; else return 0;}
    		void insert_first(int number){ if(!head){head=new node; head->prev=head->next = 0; head->value = number%100000000;}
    									else{ node *tp = first_right(); tp->next = new node; tp->next->prev = tp; tp->next->next = 0; tp->next->value = number%100000000;}}
    		void insert_last(int number) { if(!head){head=new node; head->prev=head->next = 0; head->value = number%100000000;}
    									else{node *tp = first_left();  tp->prev = new node; tp->prev->next = tp; tp->prev->prev = 0; tp->prev->value = number%100000000;}}
    };

  4. #4
    SAMARAS std10093's Avatar
    Join Date
    Jan 2011
    Location
    Nice, France
    Posts
    2,694
    Assume I have a function that is like this
    Code:
    void foo(void)
    {
            int a = 5;
            // do work
    
            // end of function
    }
    When does a gets destructed? (In other words, when does it comes out of scope..?).When the termination of the function arrives. Same thing happens with your object.

    How we deal with this? There are a few ways, but what I would suggest you is to use the new keyword, in order to dynamically allocate memory. This memory will be deallocated, until you say so (with the keyword delete).
    Code - functions and small libraries I use


    It’s 2014 and I still use printf() for debugging.


    "Programs must be written for people to read, and only incidentally for machines to execute. " —Harold Abelson

  5. #5
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    Did you implement the assignment operator? What did you code there? That could be the source of the issue: see the rule of three.

  6. #6
    Registered User
    Join Date
    Oct 2012
    Posts
    71
    the destructor is called right after the line return result;(which is the correct information) but before it gets back to the main (in between the data is wiped by my destructor). I think it might be the rule of three actually, needing a copy constructor.

    Here is my LongInt class
    Code:
    class LongInt {public:
    	int sign;
    	ADTList *mlist;
    	LongInt(){mlist = new ADTList();};
    	~LongInt(){delete mlist;};
    	int getsign(){return sign;};
    	void setsign(int i){if(i>0) sign=1; else sign = 0;};
    	LongInt add(const LongInt&);
    	void clear(){delete mlist; mlist = new ADTList();};
    	int digits(){ int i = 0; node *count = mlist->first_right(); if(!count) return 0; else{while(count->prev){count=count->prev;i=i+8;}	int j=count->value;
    	while(j>0){	j=j/10;i++;	}}return i;}
    };

  7. #7
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Yes that class needs a copy-constructor and assignment-operator.

    You really ought to stop putting all the code on one line, especially for what isn't entirely trivial code. That code's so horribly cramped up there that it makes me want to say:
    U
    S
    E

    W
    H
    I
    T
    E
    S
    P
    A
    C
    E
    !
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  8. #8
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by std10093 View Post
    How we deal with this? There are a few ways, but what I would suggest you is to use the new keyword, in order to dynamically allocate memory. This memory will be deallocated, until you say so (with the keyword delete).
    Why do you keep suggesting new? It is absolutely wrong to do that in the places you are suggesting. If you can avoid new, then do it.
    worksinotfun: This is not a minimal example. You should really comment out code line-by-line until your problem disappears. Then you can post that (without the comments). It makes it easier to see the problem.
    Also, don't use void main:
    SourceForge.net: Void main - cpwiki
    void main(void) - the Wrong Thing
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  9. #9
    SAMARAS std10093's Avatar
    Join Date
    Jan 2011
    Location
    Nice, France
    Posts
    2,694
    Because I guess I have still many things to learn... (also I admit I haven't coded in challenging Cpp for some months now..).
    Code - functions and small libraries I use


    It’s 2014 and I still use printf() for debugging.


    "Programs must be written for people to read, and only incidentally for machines to execute. " —Harold Abelson

  10. #10
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by workisnotfun View Post
    Code:
    LongInt LongInt::add(const LongInt& otherInt)
    {
    	LongInt result;
    
    
    	/* operations */
    
    
    	return result;
    }
    I ran my function through the debugger and while on return result; I hit step into and the next line goes to the destructor of my class before sending the copy outside of the function. So what gets outside is a blank object.
    Logically, what the code above does on the return statement is create a temporary copy of result (invoking copy constructor), destroy result (by invoking destructor). By some compiler-specific magic, that temporary is made available to the caller. Then, in the caller code, that temporary copy is copied into result, again using the copy constructor and the temporary is destroyed (using the destructor).

    That process relies on the destructor, the copy constructor, and (if the caller does an assignment to an existing variable rather than creating one on the spot) the assignment operator each working in tandem to ensure the caller gets the required state (i.e. the returned value).

    If your caller receives a "blank object", it means that you have not implemented the triad (copy constructor, assignment operator, and destructor) correctly, so the creation and copying of temporaries does not work correctly. It is YOUR responsibility to ensure the copy constructor, assignment operator, and destructor work together as required. The compiler will ASSUME that they do.


    Note: the sequence I described of creating temporary objects is what the standard notionally requires. The standard, however, also specifically allows a compiler to avoid creating a temporary if the only way a program can detect existence of the temporary is by tracking constructor and destructor calls. However, most compilers - when building for debugging - don't eliminate the temporaries.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  11. #11
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    The standard also says that if you return a local temporary, a move may be performed, so this instance would call the move constructor, then the destructor.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  12. #12
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by Elysia View Post
    The standard also says that if you return a local temporary, a move may be performed, so this instance would call the move constructor, then the destructor.
    In C++-11, yes.

    That doesn't change the fact that the compiler can elect not to create temporaries at all - in which case the statement
    Code:
    LongInt result = firstnumber->add(*secondnumber);
    only ever involves a single constructor call (since this statement creates a variable). All of the other temporaries that (conceivably) might be created .... need not be. So no other constructor or destructor invocations, depending naturally on how smart the compiler is (i.e. quality of the implementation).
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. destructor not called
    By rahulsk1947 in forum C++ Programming
    Replies: 8
    Last Post: 06-17-2009, 08:24 AM
  2. Why would the destructor be called?
    By therabidwombat in forum C++ Programming
    Replies: 5
    Last Post: 02-15-2009, 12:09 PM
  3. Replies: 25
    Last Post: 04-29-2008, 06:32 AM
  4. Why the destructor is called?
    By scherzo in forum C++ Programming
    Replies: 5
    Last Post: 10-23-2007, 05:11 AM
  5. returning a pointer to a destroyed variable?
    By krygen in forum C++ Programming
    Replies: 6
    Last Post: 11-06-2004, 02:22 PM