1

There is a method for deallocating memory using delete operator of c++. I wanted to test it through google test.

void freeMemory(char** test)
{
    
    for(int i=0; i<5; i++)
    {
        delete[] test[i];
    }
    delete[] test;
}

I wanted to know how to mock or test this scenario.

Ari
  • 7,251
  • 11
  • 40
  • 70
sattva_venu
  • 677
  • 8
  • 22
  • You can't check if `delete[]` call is correct. It either is correct or you invoked UB. One could check if `delete` was called using operator overloading, but it's much, *much* better to use an existing tool for detecting memory leaks, e.g. `valgrind`. And also you are much better if you don't do manual memory management, `std::vector` would take care of allocating and freeing memory for you. – Yksisarvinen Jun 08 '22 at 08:42
  • `std::vector` is also easily testable. `s.clear(); assert(s.size() == 0);` thats all you need to test if memory has been freed – 463035818_is_not_an_ai Jun 08 '22 at 09:03
  • @463035818_is_not_a_number not true... `clear()` does not necessarily frees the memory. Although a call to `size()` will return 0, a call to `capacity()` often reveals that the memory is still allocated. Proper de-allocation must be done through other ways. More details in https://stackoverflow.com/questions/10464992/c-delete-vector-objects-free-memory/63196454#63196454 – Ronald Souza Jun 08 '22 at 10:57

1 Answers1

0

I don't think you can directly validate if delete [] is called, but you can indirectly validate it by overloading the global delete [] operator, which is notorious to be unsafe, yet doable.

Here is my implementation:

//-----------------------------------------------------------------------------
// Defining the mock
//-----------------------------------------------------------------------------
// A dummy mock class whose do_delete function is called whenever delete[] is
// called.
struct MockDeletIndicator {
 public:
  MOCK_METHOD(void, do_delete, (void*), ());
};

// A global pointer that points to an object of type MockDeletIndicator.
MockDeletIndicator* global_delete_indicator = nullptr;
//-----------------------------------------------------------------------------
// Overloading the delete operator
//-----------------------------------------------------------------------------
// Globally overloading the delete operator. Not safe!
void operator delete[](void* p) throw() {
  if (global_delete_indicator != nullptr) {
    global_delete_indicator->do_delete(p);
  }
  free(p);
}
//-----------------------------------------------------------------------------
// Function under test
//-----------------------------------------------------------------------------
void freeMemory(char** test) {
  for (int i = 0; i < 5; i++) {
    delete[] test[i];
  }
  delete[] test;
}
//-----------------------------------------------------------------------------
// Tests
//-----------------------------------------------------------------------------
TEST(TestFoo, UsingAlpha) {
  // Creating a dynamic two-dimensional array.
  char** ary = new char*[5];
  for (int i = 0; i < 5; i++) {
    ary[i] = new char[5];
  }

  // Creating an object of MockDeletIndicator and store its address in
  // global_delete_indicator
  MockDeletIndicator mock_delete_indicator;
  global_delete_indicator = &mock_delete_indicator;

  // Validating if delete[] is called.
  for (int i = 0; i < 5; i++) {
    EXPECT_CALL(mock_delete_indicator, do_delete(ary[i]));
  }
  EXPECT_CALL(mock_delete_indicator, do_delete(ary));

  // Call function under test.
  freeMemory(ary);
}

Here is a live example: https://godbolt.org/z/srqaoxar9

Ari
  • 7,251
  • 11
  • 40
  • 70