Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ pure virtual method memory management question

I have a base class (AClass here) that has a protected resource (str here) that get's free'd in the AClass destructor. Derived BClass has a pure virtual Init method. Derived CClass implements Init which allocates some memory for the protected resource.

Valgrind is saying that I have 3 allocs and 2 frees. Honestly, I only explicitly see 1 alloc and 1 free, but I'll accept that there are some that I don't see (for now, but please someone explain). But, why aren't they balanced at least? Does every derived instance also have it's own str and it's not getting free'd?

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>

class AClass;
class BClass;
class CClass;

class AClass
{
public:
  AClass() : str(NULL) {
    printf("AClass Constructor with no params.\n");
    str = (char *) malloc(5 * sizeof(char)); 
  }
  AClass(char *foo) {
    printf("AClass Constructor with params, %s.\n", foo);
  }
  virtual ~AClass () {
    printf("AClass Destructor. Getting ready to free %s\n", str);
    free(str);
    printf("\tfree.\n");
  }

protected:
  char *str;
};

class BClass : public AClass
{
public:
  BClass() {
    printf("BClass Constructor with no params.\n");
  };
  BClass(char *foo) : AClass(foo) {
    printf("BClass Constructor with params, %s.\n", foo);
    str = foo;
  };
  virtual void Init() = 0;
  virtual ~BClass () {
    printf("BClass Destructor.\n");
  };
};

class CClass : public BClass
{
public:
  CClass () {
    printf("CClass Constructor with no params.\n");
  };
  void Init() {
    printf("CClass Init method.\n");
    str = (char *) malloc(255 * sizeof(char));
    printf("\tmalloc.\n");
    snprintf(str, 255 * sizeof(char), "Hello, world.");
  };
  virtual ~CClass () {
    printf("CClass Destructor.\n");
  };
};

int main (int argc, char const *argv[])
{
  printf("Start.\n");
  BClass *x = new CClass();
  x->Init();
  delete x;
  printf("End.\n");
  return 0;
}

Here's the Valgrind output.

==6641== Memcheck, a memory error detector
==6641== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==6641== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
==6641== Command: ./a.out
==6641==
Start.
AClass Constructor with no params.
BClass Constructor with no params.
CClass Constructor with no params.
CClass Init method.
        malloc.
CClass Destructor.
BClass Destructor.
AClass Destructor. Getting ready to free Hello, world.
        free.
End.
==6641==
==6641== HEAP SUMMARY:
==6641==     in use at exit: 5 bytes in 1 blocks
==6641==   total heap usage: 3 allocs, 2 frees, 268 bytes allocated
==6641==
==6641== LEAK SUMMARY:
==6641==    definitely lost: 5 bytes in 1 blocks
==6641==    indirectly lost: 0 bytes in 0 blocks
==6641==      possibly lost: 0 bytes in 0 blocks
==6641==    still reachable: 0 bytes in 0 blocks
==6641==         suppressed: 0 bytes in 0 blocks
==6641== Rerun with --leak-check=full to see details of leaked memory
==6641==
==6641== For counts of detected and suppressed errors, rerun with: -v
==6641== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 18 from 7)
like image 800
Jason Marcell Avatar asked Mar 23 '26 07:03

Jason Marcell


1 Answers

When you construct and then Init an instance of your CClass, the str pointer is first assigned a pointer from the malloc call in the AClass default constructor, and then later assigned a pointer from the malloc call in CClass::Init. The memory allocated in the AClass default constructor is never freed, and the pointer is lost when str is overwritten in CClass::Init.

You could check for a non-NULL value in the str pointer before re-assigning it in CClass::Init. Alternatively, you could encapsulate str assignment in a member function that performs this check, so that this concern doesn't arise elsewhere:

void allocate_str(int size) {
   if (str) free(str);
   str = (char*) malloc(size * sizeof(char));
}

Better yet, you could make use of the C++ run-time library's many modern features, including string objects and smart pointers.

like image 154
Jollymorphic Avatar answered Mar 24 '26 21:03

Jollymorphic



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!