4

I have issues with my destructor in my c++ program.When I run the program and take the users input, it suddenly calls the destructor before the cout can even print inside the statement. Assume that the user input will be one because I designed this part of the code to only take in the input 1. I thought the destructor gets called when you leave the scope so I was thinking that the destructor should be called atleast after the cout in the if statement which I will comment below to make it easier for you guys to read. If someone can explain my mistake and correct it that would be great! In my headerfile I have

#include <iostream>
#include <string>
#include <stdlib.h>
#include <time.h>

using namespace std;

class creature{
public:
    creature();//default constructor
    creature(int a);
    ~creature();//desconstructor 
    string getName();//accessor for the name
    static int getNumObjects();
private:
    string name;
    int happy_level;
    static int count;
};

In my implementation file I have

#include "creature.h"

int creature::count=0;//initialize static member variable

creature::creature(){//default constructor
    name="bob";
    ++numberobject;
    
    cout<<"The default constructor is being called"<<endl;
}

creature::creature(int a)
{
    if(a==1)
    {
        name="billybob";
       
    }
    
    
    else if(a==2)
    {
        name="bobbilly";
       
    }
    
    else if(a==3)
    {
        name="bobbertyo";
        happy_level=1;
    }
}

creature::~creature()
{
    cout<<"The destructor is now being called"<<endl;
    cout<<creature::getName()<<" is destroyed."<<endl;
     --count;
    cout<<"Now you have a total number of "<<creature::getNumObjects()<<" creature"<<endl;
}

and in my main class I have

#include "creature.h"

int main()
{

   creature foo;//this is where the default constructor gets called which is good
   int choice;
   
   cout<<"enter 1 2 or 3 to choose ur monster"<<endl;
   cin>>choice;

   foo=creature(choice);

   if(choice==1)
    {
        cout<<"hi"<<endl;//the destructor gets called before hi is printed out and I don't know why thats happening
    }

}
peterh
  • 11,875
  • 18
  • 85
  • 108
Brogrammer93
  • 97
  • 1
  • 2
  • 9
  • 1
    it's called a "destructor". – The Paramagnetic Croissant May 27 '15 at 20:25
  • 2
    In `foo = creature(choice);`, you create an anonymous instance (`creature(choice)`), invoke `creature & operator=(const creature &)` on `foo`, and then destroy the anonymous instance. Also, it's "destructor", BTW. – набиячлэвэли May 27 '15 at 20:28
  • Your `count` variable doesn't reflect what is really going on. You failed to add a copy constructor and assignment operator to count those instances. Instead, you're decrementing count for object instances you didn't even track. – PaulMcKenzie May 27 '15 at 20:28
  • @TheParamagneticCroissant: That is hardly worth pointing out. Even without context, `deconstructor` perfectly describes what it is. – wallyk May 27 '15 at 20:29

3 Answers3

10

When you do this

foo=creature(choice);

a temporary creature object is created on the RHS of the assignment. Its destructor is called once the statement is done, i.e. at end of the line.

There isn't really anything to fix, but you can initialize foo after reading in choice, rather than default initializing and then assigning:

int choice;

cout<<"enter 1 2 or 3 to choose ur monster"<<endl;
cin>>choice;

creature foo(choice);
juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • isn't the original `creature` (`foo`) being destoyed? – Amit May 27 '15 at 20:28
  • @Amit It gets destroyed when `main()` exits, not during the statement shown. – juanchopanza May 27 '15 at 20:30
  • 1
    @Amit No, it's pretty much equivalent to `creature __anon(choice); foo.operator=(__anon); __anon.~creature();`. – набиячлэвэли May 27 '15 at 20:32
  • 1
    @Darraptor because `choice` wouldn't have a useful value. – juanchopanza May 27 '15 at 20:54
  • @juanchopanza oh shoot ur right lol well thank you so much I get your explanation and got my code to almost work(I just need to add more stuff in but I can handle that) – Brogrammer93 May 27 '15 at 20:57
  • @Darraptor Also remember that your `count` variable is not correct. You need to add the user-defined copy constructor and assignment operator, else your `getNumObjects` will return an unexpected value (it may return 0 instead of 1). – PaulMcKenzie May 27 '15 at 21:02
  • @PaulMcKenzie why would I get an unexpected value from count though? I made sure count was declared correctly – Brogrammer93 May 27 '15 at 21:55
  • @Darraptor See my answer. Objects are being created at times where you are not tracking the creation. What will happen is that you are subtracting 1 from count from an object you didn't know existed, but its destructor was called anyway. – PaulMcKenzie May 27 '15 at 22:07
  • @PaulMcKenzie I'm alittle confused when u said user defined copy and assignment? Like I know what they are but I don't get what u mean by user defined. Can you show me an example? – Brogrammer93 May 27 '15 at 22:17
  • @Darraptor That line of code that does this `foo = creature(choice)` It is doing a lot more than what you think. It is creating temporary creature objects. Without a user defined copy constructor and assignment operators to track the creation, your `count` will be off. By `user-defined` I mean that you are overriding the compiler default versions (which is what was being invoked in your original code). We don't want that -- we need to also track the count, so you have to provide replacement functions instead of the compiler version of these functions. – PaulMcKenzie May 27 '15 at 22:19
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/78958/discussion-between-darraptor-and-paulmckenzie). – Brogrammer93 May 27 '15 at 22:34
  • Perfect explanation. Thanks. – Berdan Akyürek Mar 06 '21 at 21:01
2

As juanchopanza pointed out in his answer, the line

foo = creature(choice);

creates a temporary creature object before assigning it to foo. If you don't want this to happen, create it with

creature foo(choice);
1

To add to the other answers, your question referred to "fixing the destructor". There is nothing to fix, however there may be a bug in what you're trying to accomplish due to the destructor being invoked.

What will happen with your current code is that temporary copies may be created without you tracking them. When their destructor is called, you will decrement the count variable inadvertently, possibly giving you a negative value for count.

If you want the object static count member variable to correctly reflect the number of objects created and destroyed, your class is missing a user defined copy constructor to track the number of instances.

You need to add this function.

class creature{
public:
    creature(const creature& c) : 
         name(c.name), happy_level(c.happy_level) { ++count; }
};

This function will be called when you make copies or assign.

Live Examples:

(original code): http://coliru.stacked-crooked.com/a/ea9821e622aa4cdc

(changed code): http://coliru.stacked-crooked.com/a/b774a896377bdf97

The only difference is that the original code has the copy constructor commented out, while the changed code has the copy constructor intact.

Note that in the original code, I wanted to know how many objects are created and destroyed, but I got back a result of -1 when the final object was destroyed. This is not correct as obviously the result should yield 0, meaning all creatures are destroyed.

The changed code shows the correct number, and that is because the object creation of the temporary creature was taken into account.

PaulMcKenzie
  • 34,698
  • 4
  • 24
  • 45