2

I have a Containing class, a Contained class, and a Data class. That Containing class holds a vector of Contained objects. The Contained class holds a pointer to a data object, allocated on the heap in Contained's constructor. However, I can't deallocate it in the destructor, since the vector will create copies of Contained and then destroy them, thus destroying the data pointer even in the copy we're using.

TL;DR Here's some code to explain:

class Data {
    public:
        Data();
};

class Contained {
    private:
        Data* data;
    public:
        Contained();
        // what should I add ? a copy constructor ? an assignement operator ? and how
};

class Container {
    private:
        vector<Contained> rooms;
    public:
        //some member functions
};
Contained::Contained() {
    data = new Data();
}

Where do I delete data ?

Vélimir
  • 409
  • 3
  • 12
  • 1
    Related: please read about [RAII](https://en.cppreference.com/w/cpp/language/raii) and the [rule of 3/5/0](https://en.cppreference.com/w/cpp/language/rule_of_three). – G.M. Mar 29 '20 at 14:27
  • Have you considered `std::shared_ptr`? – Jesper Juhl Mar 29 '20 at 14:28
  • @G.M. I googled my problem beforehand and found the exact same "rules" article, but had trouble figuring out how to apply it to my case. Thanks for linking to RAII though ! – Vélimir Mar 29 '20 at 15:07
  • @JesperJuhl My goal was to use the pointer as a two dimentionnal array. I never used smart pointers before, so I didn't know if it could resolve my problem. I'll dig out on this side too ! Thanks a lot – Vélimir Mar 29 '20 at 15:08

1 Answers1

1

Using RAII(Resource Acquisition is Initialization)

Add a destructor to the Contained class:

Contained::~Contained() {
    delete data;
}

This will ensure whenever your contained object goes out of scope, it will automatically delete the data pointer it has. So if you do

//delete first element
rooms.erase(rooms.begin());

data ptr of that object will automatically be deleted.

Using smart pointers

Use std::unique_ptr<T>.

class Contained {
    private:
        std::unique_ptr<Data> data;
    public:
        Contained();
        // what should I add ? a copy constructor ? an assignement operator ? and how
};

and in the constructor:

Contained::Contained() {
    data = std::make_unique<Data>();
}

Using smart pointers i.e., (unique_ptr, shared_ptr) ensures your pointer will automatically delete when no one is owning it. Since you can not copy unique_ptr but only move it, you should define a move constructor and move assignment operator on the Contained class.

Contained::Contained(Contained&& other) 
    : data(std::move(other.data))
{}

Contained& operator=(Contained&& rhs) {
    if (this != &other) {
        data = std::move(rhs.data);
    }
    return *this;
}
Waqar
  • 8,558
  • 4
  • 35
  • 43
  • Thanks a lot for the quick answer ! However, I can't really understand how the first case works. If the vector moves in memory, it will copy each of its entries, therefore calling the Contained destructor... What I meant by "However, I can't deallocate it in the destructor, since the vector will create copies of Contained and then destroy them, thus destroying the data pointer even in the copy we're using." – Vélimir Mar 29 '20 at 15:02
  • The second way seems interesting though, I'll test it, and if it works accept your answer. **But I'm wondering if smart pointers can be used for arrays ?** The data pointer is in my real model a Data **data, meant to store a two dimentionnal array. – Vélimir Mar 29 '20 at 15:04
  • It will destroy as soon as it moves out of scope. However you can move it around using reference / pointer and extend its lifetime. As long as your `Container` class lives, the data ptrs inside it will also live. – Waqar Mar 29 '20 at 15:07
  • 1
    Double ptrs cant be used with std::unique_ptr, however I may be wrong since I haven't tested it. https://stackoverflow.com/questions/9794267/double-two-dimensional-array-using-stdunique-ptr seems interesting. You might be able to find your answer there. – Waqar Mar 29 '20 at 15:12