0

I got a template class Atlas that will store objects of Animal class and derived classes of Animal; here's the code:

#include <iostream>
#include <assert.h>
#include <list>
using namespace std;
class Animal {
protected:
    std::string m_name;
    Animal (std::string name): m_name {name} {}
public:
    virtual std::string regn() const { return "???"; }
    virtual ~Animal(){
    cout << "Destructor animal"<<'\n';}
};
class Nevertebrate : public Animal{
public:
    virtual std::string regn() const { return "nevertebrate";}
    virtual ~Nevertebrate();
};
class Vertebrate: public Animal {
protected:
  /*  std::string m_name;
    Vertebrate (std::string name)
        :m_name {name} {} */
        Vertebrate (std::string name)
            : Animal {name} {}

public:
    virtual std::string regn() const { return "vertebrate";}
    virtual ~Vertebrate(){
    cout<<"Destructor vertebrate"<<'\n';};
};


class bird: public Vertebrate {
public:
    bird(std::string name)
        : Vertebrate{ name }{}
    void set_name (std::string nume){
    m_name = nume;}

    std::string get_name(){
    return m_name;}
    virtual std::string regn() const {return "pasare";}
    virtual ~bird (){
    cout << "destructor bird"<<'\n';}
 };

template <class T>
class Atlas
{
private:
    int m_length{};
    T* m_data{};

public:
    void SetLength(int j);
    Atlas(int length)
    {
        assert(length > 0);
        m_data = new T[length]{};
        m_length = length;
    }

    Atlas(const Atlas&) = delete;
    Atlas& operator=(const Atlas&) = delete;

    ~Atlas()
    {
        delete[] m_data;
    }

    void erase()
    {
        delete[] m_data;

        m_data = nullptr;
        m_length = 0;
    }

    T& operator[](int index)
    {
        assert(index >= 0 && index < m_length);
        return m_data[index];
    }

    int getLength() const;
};
template <class T>
int Atlas<T>::getLength() const  
{
  return m_length;
}
template <class T>
void Atlas<T>::SetLength(int j){m_length = j;
}

int main()
{
   Atlas<Bird> AtlasBird(10);
   Bird b;
   AtlasBird.SetLength(11);
   AtlasBird[10] = b      --- it gets a memoryleak from here.
    return 0;
}

I want to overload the += operator so that i can insert a new object into my Atlas, (e.g. AtlasAnimal). I tried with the SetLength function to increase the length, (e.g. AtlasAnimal.SetLength(11)) but when i try to assign AtlasAnimal[10] an object (e.g. Bird b) it drops a memory leak.

I'm sorry if there was a similar question answered, but i couldn't find anything that helps

  • When you change the size you need to reallocate the memory. – Some programmer dude May 17 '21 at 08:20
  • @Someprogrammerdude but wouldn't that make a new Atlas object that will delete my already stored data? I mean if i got 3 animals already in that template, when i reallocate the memory to insert a new one and make ```m_ data = new T[4]``` , wouldn't that make me lose my already stored animals? **Edit: Nope, that's perfect. I thank you very much!** – Dragos Polifronie May 17 '21 at 08:26
  • 1
    Precisely, and that's why there is a `std::vector` implementation that does that automatically for you. Every time your item count outgrows your allocated buffer, you have to create a new, larger, buffer and move the items from the old buffer into the new one. Btw, why don't you use `std::vector`? – Timo May 17 '21 at 08:32
  • No you allocate a *new* array of `current_length + 1` elements, and copy existing elements to that new array. Then you delete the old array and assign `m_data` to the new array. The `Atlas` object would still be the same. – Some programmer dude May 17 '21 at 08:32
  • now i got it, didn't realise how this works, i appreciate the extra explanation. @Timo I want to get used with creating and using template classes and i found this as a good and easy example. – Dragos Polifronie May 17 '21 at 08:40
  • You can still do that of course. I meant changing `m_data` to be of type `std::vector` instead of `T*`. This way you could also get rid of the `m_length` member, since `std::vector` has one on its own. – Timo May 17 '21 at 08:48
  • Hm i think that would actually work. I want to make this ```vector``` to store different objects of classes derived from ```base class animal```, for e.g. i want to store 2 birds and 3 dogs in the same vector(just an example, cause i didn't even create the ```dog class``` yet) and i'm still trying to figure out all of that and find a suitable solution. – Dragos Polifronie May 17 '21 at 08:54
  • Then you need to store the pointers of the base class: `animal`, or with c++17 `variant` – prehistoricpenguin May 17 '21 at 08:57
  • I'm using c++11, i still can't figure out why ```Atlas AtlasAnimal(1); Bird b; cout << p.regn()<<'\n'; b.set_name("Eagle"); AtlasAnimal[0] = b; cout << AtlasAnimal[0].get_name() << AtlasAnimal[0].regn() << '\n';``` in this code above, ``` AtlasAnimal[0].get_name()``` prints "Eagle" but ``` AtlasAnimal[0].regn()``` prints "????" From the base Animal class instead of the overrided function in Bird class. The overriding is done corectly, as b.regn() prints "Pasare" when tested. – Dragos Polifronie May 17 '21 at 10:19
  • Because the `Atlas` object stores `Animal` objects, any objects from a child-class will be [*sliced*](https://stackoverflow.com/questions/274626/what-is-object-slicing). If you want to store objects of child-classes and use polymorphism you need to store *pointers* to objects instead. – Some programmer dude May 17 '21 at 12:08
  • I saw that after a few hours of researching and trying tons of ''solutions'' for that. I'm a little confused, how should i work with pointers in this case? Cause for `animal` and derived classes (like `Bird`) i did not allocate memory (i.e. did not use dinamyc allocation when creating objects of those classes), i allocate only for the vector :/ I also tried to create 2 new template classes, one as Node and another as List, but the result is the same. – Dragos Polifronie May 17 '21 at 14:39

0 Answers0