HashBr0wn
HashBr0wn

Reputation: 467

does calling delete on an object pointer recursively delete its dynamically allocated members

If I have a class A that contains a dynamically allocated instance of class B, does calling delete on a pointer to an instance of A (received from new of course) also effectively deallocate the memory occupied by the instance of B? Or does the destructor of A have to explicitly call delete on the instance of B in order for that to happen?

Upvotes: 0

Views: 293

Answers (1)

cdhowie
cdhowie

Reputation: 168988

That depends on how you're storing the pointer to B within the A type.

class B;

class A {
private:
    SomePointer m_b;
};

What is SomePointer?

  • If it's B* then no, deletion of this B allocation is not automatic. You would need to implement the destructor A::~A() and delete it there. Don't forget to delete/implement the copy/move construction/assignment functions as well, or a copy/move operation will result in two As owning the same B and that leads to (among other things) the double-free problem.
  • If it's std::unique_ptr<B> then congratulations, you made the right choice and you don't have to do anything. A's implicitly-defined destructor will destroy the std::unique_ptr<B> which will delete the allocated B for you. Additionally, the move constructor/assignment functions will be implicitly defined correctly (assuming the rest of the data members of A are movable) and A's copy operations will be implicitly deleted as they would be ill-formed (std::unique_ptr<B> is not copyable).

Here's an example of the two approaches. They both allow the same operations on A. First, using a raw pointer:

class A {
public:
    A();

    // Need custom move logic.
    A(A &&);
    A & operator=(A &&);

    // Prevent copying.
    A(A const &) = delete;
    A & operator=(A const &) = delete;

    ~A();

private:
    B * m_b;
};

A::A() : m_b{nullptr} { }

A::~A() { delete m_b; }

A::A(A && other) : A{} { *this = std::move(other); }

A & A::operator=(A && other) {
    using std::swap;
    swap(m_b, other.m_b);
    return *this;
}

Now using std::unique_ptr<B>:

class A {
private:
    std::unique_ptr<B> m_b;
}

Which one would you rather maintain? Which one is easier to get right?

Upvotes: 3

Related Questions