【问题标题】:C++ pure virtual method memory management questionC++纯虚方法内存管理问题
【发布时间】:2011-04-09 20:19:50
【问题描述】:

我有一个基类(这里是AClass),它有一个protected 资源(这里是str),它在AClass 析构函数中得到free。派生的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 %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;
}

这是 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)

【问题讨论】:

  • 当你打开--leak-check=full选项时会发生什么?
  • 有点不相关,但是您使用 char* 而不是 std::string 有什么原因吗?
  • AClass 的构造函数中有一个malloc。你为什么不为那个mallocprintf("\tmalloc.\n") 呢?这就是您在程序输出中看不到不平衡的malloc 的原因。
  • 另外,当您的整个程序中只有一个类实例时,您所说的“每个派生实例”是什么?
  • @MahlerFive,对 C++ 有点陌生,周围没有任何其他 C++ 开发人员,我求助于 Google 的 C++ 样式指南 (bit.ly/eMAtAy)。我也对他们对此的呼吁表示怀疑,如果您愿意,我很乐意在不同的论坛上讨论它。

标签: c++ inheritance memory-leaks valgrind


【解决方案1】:

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

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

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

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

【讨论】:

    【解决方案2】:

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

    1. new CClass in main
    2. mallocAClass 构造函数中。
    3. mallocCClass::Init

    至于调用不平衡的原因:您正在泄漏 str,这是在 AClass 构造函数中分配的 - 您正在更改 str 中的 str 指针:

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

    无需先释放先前分配的缓冲区。

    【讨论】:

    • 感谢您明确列出 3 个分配。我想我可以通过 Valgrind 上的一些额外命令行开关来解决这个问题,但我仍在学习如何解释它的输出。
    【解决方案3】:

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

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

    在你的初始化中,当你这样做时你会失去它

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

    第三个alloc(第二个free)是CClass的new和delete

    【讨论】:

      猜你喜欢
      • 2012-07-23
      • 2011-05-11
      • 2011-03-13
      • 1970-01-01
      • 1970-01-01
      • 2011-09-08
      • 2018-03-31
      • 2015-12-09
      相关资源
      最近更新 更多