C++纯虚方法内存管理问题

Jas*_*ell 3 c++ inheritance valgrind memory-leaks

我有一个基类(AClass这里)有一个protected资源(str这里)freeAClass析构函数中获取.Derived BClass有一个纯虚Init方法.派生的CClass实现Init为受保护资源分配一些内存.

Valgrind说我有3个分配和2个释放.老实说,我只明确地看到1个alloc和1个free,但我会接受有一些我看不到的(现在,但请有人解释).但是,为什么他们至少不平衡?每个派生的实例是否也拥有自己的实例str并且它没有得到它free

#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;
}
Run Code Online (Sandbox Code Playgroud)

这是Valgrind的输出.

==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)
Run Code Online (Sandbox Code Playgroud)

Jol*_*hic 5

当你构造你的Init一个实例时CClass,str首先mallocAClass默认构造函数中为指针分配一个指针,然后从malloc调用中分配一个指针CClass::Init.AClass永远不会释放在默认构造函数中分配的内存,并且在str覆盖时指针会丢失CClass::Init.

您可以str在重新分配指针之前检查指针中的非NULL值CClass::Init.或者,您可以将str赋值封装在执行此检查的成员函数中,以便在其他地方不会出现此问题:

void allocate_str(int size) {
   if (str) free(str);
   str = (char*) malloc(size * sizeof(char));
}
Run Code Online (Sandbox Code Playgroud)

更好的是,您可以利用C++运行时库的许多现代功能,包括字符串对象和智能指针.


Cat*_*lus 5

这与虚函数没有任何关系.Valgrind检测到的三个分配是:

  1. new CClassmain.
  2. mallocAClass构造函数中.
  3. mallocCClass::Init.

至于为什么调用不平衡:你正在泄漏str那些在AClass构造函数中分配的东西- 你正在改变str指针CClass::Init:

void Init() {
    // ...
    str = (char *) malloc(255 * sizeof(char));
    // ...
};
Run Code Online (Sandbox Code Playgroud)

没有先释放先前分配的缓冲区.