-1

I've written two class. In Basic class I have attribute age, which is dynamically allocated. I try to use it in class Dog. The code executes but it gives me output:

mammal create 
dog create 
how 
2
dog delete 
mammal delete 
munmap_chunk(): invalid pointer
Aborted (core dumped)

What is the problem with my code, how should I change it to not have problem with pointer.

Here is my code:

#include <iostream>

class Mammal
{
    public:

        Mammal(int nAge);
        ~Mammal();

        int getAge();
        void setAge(int nAge);

    private:

        int *age;
};


Mammal::Mammal(int nAge)
{
    int *age = new int;
    age = &nAge;
    std::cout<<"mammal create \n";
}

Mammal::~Mammal()
{
    std::cout<<"mammal delete \n";
    delete age;
}

int Mammal::getAge()
{
    return *age;
}

void Mammal::setAge(int nAge)
{
    age = &nAge;
}

class Dog : public Mammal
{

    public:

        Dog();
        ~Dog();
        void  getVoice();
};

Dog::Dog ()
{
    std::cout << "dog create \n";

}

Dog::~Dog()
{
    std::cout<<"dog delete \n";
}

void Dog::getVoice()
{
    std::cout<<"how \n";
}

int main()
{
    Dog* dog = new Dog;
    dog -> getVoice();
    dog -> setAge(2);
    std::cout<<dog-> getAge()<<"\n";

    delete dog;
}

Summary I'd like to understand how memory allocation work with inheritance.

Cœur
  • 37,241
  • 25
  • 195
  • 267
alekq
  • 137
  • 2
  • 15
  • Not the issue you are facing right now, but note that your class is wrong the way it is now and will cause undefined behavior when used in certain ways, because it doesn't follow the [rule-of-three](https://stackoverflow.com/questions/4172722/what-is-the-rule-of-three) – walnut Aug 30 '19 at 17:44
  • 1
    The posted code is different than whatever gives you the error you state: test.cpp(55): error C2512: 'Mammal': no appropriate default constructor available – Jeffrey Aug 30 '19 at 17:46
  • 2
    Everywhere you have age = &nAge should be replaced with *age = nAge. – John Sheridan Aug 30 '19 at 17:46
  • 1
    If there is no specific good reason for it, `age` shouldn't be a pointer at all. It should be just an `int`, or if it must be an owning pointer `std::unique_ptr`. – walnut Aug 30 '19 at 17:49
  • Can you prompt me when is a good reason to use it except dynamic allocation, or when dynamic memory allocation is not good reason – alekq Aug 30 '19 at 18:33

3 Answers3

3

In the constructor you have these two lines

int *age = new int;
age = &nAge;

They lead to three problems:

First of all you define a completely different and unique variable name age that is totally separate from the member variable of the same name.

Second you you overwrite the pointer with the pointer to nAge. That means you lose the original pointer you have allocated and have a memory leak.

The third problem is that you make age point to the local variable nAge. The variable nAge will end its life as soon as it goes out of scope when the function returns. Any pointer to that variable will become invalid.

To solve your problem, the easiest solution is to initialize and allocate simultaneously:

age = new int(nAge);

Or if you need to do it in two steps:

age = new int;
*age = nAge;   // Copy the value of nAge into the memory pointed to by age

As noted in a comment this is still not really a good solution, because copying of the object will lead to problems if you use the default copy-constructor of copy-assignment operator which just copies the pointer itself, and doesn't allocate new memory.


As for the inheritance there are also a couple of problems... The first is that Mammal doesn't have a default constructor, which the child class Dog relies on. The easy solution here is to make a Mammal default constructor. You could also make the Dog constructor use the parameterized Mammal constructor through the Dog constructor initializer list:

Dog::Dog()
    : Mammal(0)  // Initializes with a default age of zero
{
}

Then the Mammal destructor needs to be virtual or it won't be called when the Dog object is destructed, leading to a memory leak.

And to continue the setAge function doesn't check if the memory for age have been allocated or not. It also contains the third problem listed above with the constructor, in that it makes age point to the local variable nAge, which will disappear when the function returns.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
2

The error is in these two functions:

Mammal::Mammal(int nAge)
{
    int* age = new int;
    age = &nAge;
    std::cout<<"mammal create \n";
}

void Mammal::setAge(int nAge)
{
    age = &nAge;
}

The age pointer points to the local variable nAge. That variable dies at the end of the scope (after the }).

Also, I think you want to assign into Mammal::age, but you're creating a new variable there.

What you should do is this:

Mammal::Mammal(int nAge)
{
    age = new int;
    *age = nAge;
    std::cout<<"mammal create \n";
}

void Mammal::setAge(int nAge)
{
    *age = nAge;
}

This will assigned the allocated variable to the value of nAge, and also correctly assign the member.

Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
-1

Now it works, without errors

#include <iostream>

class Mammal
{
    public:

        Mammal(int nAge);
        virtual ~Mammal();
        Mammal(Mammal&);

        int getAge();
        void setAge(int nAge);

    private:

        int *age;
};


Mammal::Mammal(int nAge)
{
    age = new int(nAge);
    std::cout<<"mammal create \n";
}

Mammal::~Mammal()
{
    std::cout<<"mammal delete \n";
    delete age;
}

Mammal::Mammal(Mammal& rhs)
{
    age = new int;
    *age = rhs.getAge();
}

int Mammal::getAge()
{
    return *age;
}

void Mammal::setAge(int nAge)
{
    *age = nAge;
}

class Dog : public Mammal
{

    public:

        Dog();
        ~Dog();
        void  getVoice();
};

Dog::Dog ():Mammal(0)
{
    std::cout << "dog create \n";
}

Dog::~Dog()
{
    std::cout<<"dog delete \n";
}

void Dog::getVoice()
{
    std::cout<<"how \n";
}

int main()
{
    Dog* dog = new Dog;
    dog -> getVoice();
    dog -> setAge(2);
    std::cout<<dog-> getAge()<<"\n";

    delete dog;
}

Can someone check, if now everything is alright?

alekq
  • 137
  • 2
  • 15
  • Please edit your question and/or comment on the answer you are referring to, instead of writing a non-answer. – walnut Aug 30 '19 at 18:04