c++纯虚拟方法内存管理问题

C++ pure virtual method memory management question

本文关键字:管理 问题 内存 方法 虚拟 c++      更新时间:2023-10-16

我有一个基类(这里的AClass),它有一个protected资源(这里的str),它在AClass析构函数中获得free 'd。派生的BClass有一个纯虚的Init方法。派生CClass实现Init,为受保护的资源分配一些内存。

Valgrind说我有3个分配和2个自由。老实说,我只有显式地看到1个alloc和1个free,但我接受有一些我没有看到(现在,但请有人解释一下)。但是,为什么它们不平衡呢?是否每个派生实例也有它自己的str,它没有得到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 %sn", 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;
}

下面是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)

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

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

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

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

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

  1. new CClass in main .
  2. malloc in AClass constructor.
  3. malloc in CClass::Init .

至于为什么调用不平衡:你正在泄漏str,在AClass构造器中分配-你正在改变CClass::Init中的str指针:

void Init() {
    // ...
    str = (char *) malloc(255 * sizeof(char));
    // ...
};

AClass的默认构造函数有这样一行:

 str = (char *) malloc(5 * sizeof(char)); // hey, 5 bytes!

在你的Init中,当你这样做的时候,你失去了它

 str = (char *) malloc(255 * sizeof(char));

第三个alloc(第二个free)是CClass

的new和delete操作。