1

In the following class, the contractor should take a string and int ("Jan",24) from the main function. But it seems there is something wrong when the integer is passed, because another random integer like 1 gets printed as age.

    #include <iostream>
    #include <string>
    using namespace std;

    class Human{
    private:
        string *name;
        int *age;
    public:
        Human(string iname, int iage){
            name = new string;
            age = new int;

            name = &iname;
            age = &iage;
        }

        void display(){
            cout << "Hi I am "<<*name<<" and i am "<<*age<<" years old"<<endl;}

        ~Human(){
            delete name;
           delete age;
           cout << "all memories are released"<<endl;
       }
    };

    int main()
    {
        Human *Jan = new Human("Jan",24);
        Jan->display();
        delete Jan;

       return 0;
     }

The output is as follows, and age instead of 24 is printed 1. Any idea why?

    Hi I am Jan and I am 1 years old
    untitled(5417,0x7fff8ed19340) malloc: *** error for object 
    0x7ffeed4c19b8: pointer being freed was not allocated
    *** set a breakpoint in malloc_error_break to debug

I know if I change my constructor to the following it will work as expected(age=24), but I am interested to know why the above code does not work and print age=1.

    Human(//the same parameter as before)
    {
      //the same memory allocation
      *name = iname;
      *age = iage;
      }

My second question is why the distructor is not get released in the first code?

sepideha
  • 1,669
  • 1
  • 11
  • 14

1 Answers1

5

Because you are taking an address of temporary variable in your constructor. For both name and age fields.

Human(string iname, int iage){
    name = new string;
    age = new int;
    name = &iname;
    age = &iage;
}

when it was invoked as Human("Jan", 24).

After that instruction is finished, the addresses of Jan and 24 are no longer valid - means they could be pointing to anything.

Just copy the value:

class Human {
private:
    string name;
    int age;
...

An alternative solution is if you can extend the life of your (currently temporary) variables:

{
  string name = "Jan";
  int age = 24;
  {
    Human *Jan = new Human(name, age);
    Jan->display();
    delete Jan;
  }
  // &name and &age still valid, until closing bracket
}
// &name and &age no longer valid

Or alternatively, you could allocate them on heap via new, but then you need to take care of them on your own.


See Can a local variable's memory be accessed outside its scope? and other similar questions regarding variable scoping, visibility and RAII.

Adam Kotwasinski
  • 4,377
  • 3
  • 17
  • 40