How do you safely clear an object from memory (with attributes) which was created using the new keyword?

Viewed 214

As far as I know on this topic, every "new" call needs a corresponding "delete" call to that object. So is this really correct?:

using namespace std;

class Box {
   public:
      double length;
      char letters_in_box[80];
};

int main() {
   Box *b = new Box;
   b->length = 2.0;
   b->letters_in_box = "Hello world";

   //Some code with b

   delete b;

   return 0;
}

Is the memory associated with the "length" double and "letters_in_box" array cleared with this?

3 Answers

Yes. When you delete b it deletes also letters_in_box array.

But, for your b->letters_in_box = "Hello world"; you will get a compile error: "error C3863: array type 'char [80]' is not assignable"

#include <memory> // For 'memcpy_s' (since C11)

class Box
{
public:
    double length;
    char letters_in_box[80];
};

int main()
{
    Box* b = new Box;

    b->length = 2.0;
    // b->letters_in_box = "Hello world"; ** Compile Error C3863: array type 'char [80]' is not assignable **
    memcpy_s(b->letters_in_box, sizeof(b->letters_in_box), "Hello world", sizeof("Hello world"));

    // Some code with b

    delete b;
}

MODERN C++

A better practice than new is smart pointers, than for example you don't have to bother with delete in case of exception and at all:

#include <memory> // For 'std::unique_ptr' and for 'memcpy_s'

class Box
{
public:
    double length;
    char letters_in_box[80];
};

constexpr char my_text[] = "Hello world"; 

int main()
{
    auto b = std::make_unique<Box>(); // No need to delete

    b->length = 2.0;
    memcpy_s(b->letters_in_box, sizeof(b->letters_in_box), my_text, sizeof(my_text));

    // Some code with b
}

Also, (instead of C array) I prefer to use C++ array:

#include <array>  // For 'std::array'
#include <memory> // For 'std::unique_ptr' and for 'memcpy_s' 

class Box
{
public:
    double length;
    std::array<char, 80> letters_in_box;
};
   
constexpr char my_text[] = "Hello world";

int main()
{
    auto b = std::make_unique<Box>(); // No need to delete

    b->length = 2.0;
    memcpy_s(&b->letters_in_box, b->letters_in_box.size(), my_text, sizeof(my_text));

    //Some code with b
}

--

One last comment: Without a constraint to use char[], I would use std::string instead:

#include <string> // For 'std::string'
#include <memory> // For 'std::unique_ptr' 

class Box
{
public:
    double length;
    std::string letters_in_box;
};

int main()
{
    auto b = std::make_unique<Box>(); // No need to delete

    b->length = 2.0;
    b->letters_in_box = "Hello world";

    //Some code with b
}

In modern C++ it is highly recommended not to use new and delete for the reason that Karen has alluded to above, if an exception occurs for whatever reason during the program, and your exception handling causes a branch that does not return back to run delete, then this causes a memory leak.

Instead I would look into using smart pointers (https://en.cppreference.com/book/intro/smart_pointers) for creating new pointers to objects used, as these will allow for the de-allocation of memory once they go out of scope (unique pointers) (i.e. an exception branch followed by not returning to the same scope), or once their number of 'references' expires (shared pointers).

With respect to the explicit code you have written, yes once that class is deleted the "length" double and "letters_in_box" array will be deleted, however it is important to note that if you have explicitly used malloc/calloc/etc for allocating memory, then a class destructor should be used in order to free this memory.

Edit: Also would strongly recommend reading RAII (https://en.cppreference.com/w/cpp/language/raii) as it is really is the foundation of modern, safe C++.

So is this really correct?

Yes, it is correct. However, you have to make sure that it is not thrown an exception before deleting the b.

For example:

Box *b = new Box;
b->length = 2.0;
b->letters_in_box = "Hello world";

throw 5; //this is not usually done.

delete b;

In this example, if the exception is not handled before calling delete, a memory leak will occur.

Related