2011-04-09 25 views
3

私はAClassデストラクタでのfree D」を得るprotectedリソース(ここではstr)を持つベースクラス(ここではAClass)を持っています。 Derived BClassには、純粋な仮想Initメソッドがあります。 Derived CClassは、保護されたリソースにいくらかのメモリを割り当てるInitを実装しています。C++の純粋仮想メソッドのメモリ管理の問題

私は3つのallocsと2つの解放を持っているとValgrindは言っています。正直なところ、私はを明示的にとし、1つのallocと1のfreeを参照していますが、私には見られないものがあります(今は誰か説明してください)。しかし、なぜ彼らare not バランス少なくとも?派生したすべてのインスタンスにも自分自身の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; 
} 

ここにValgrind出力があります。あなたはCClassのインスタンスを作成し、その後Initとき

==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) 
+0

'--leak-check = full'オプションを有効にすると何が起こりますか? –

+1

一種の無関係ですが、std :: stringではなくchar *を使用している理由はありますか? – MahlerFive

+0

'AClass'のコンストラクタに' malloc'があります。なぜ 'malloc'の' printf( "\ tmalloc。\ n") 'もやっていないのですか?これがあなたのプログラムの出力であなたの不均衡な 'malloc'を見ることができない理由です。 – AnT

答えて

5

strポインタが最初AClassデフォルトコンストラクタでmalloc呼び出しからポインタを割り当てられ、その後CClass::Initmalloc呼び出しからポインタが割り当てられます。 strCClass::Initに上書きされると、AClassデフォルトコンストラクタに割り当てられたメモリは解放されず、ポインタは失われます。

CClass::Initに再割り当てする前に、strポインタでNULL以外の値を確認できます。

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

をいっそのこと、あなたはC++ランタイムライブラリの多くの近代的な機能を利用することができます。また、あなたは、この懸念は、他の場所で発生しないように、このチェックを実行するメンバ関数でstr割り当てをカプセル化することができ文字列オブジェクトとスマートポインタを含む。

+0

std :: stringを推薦するための+1 –

5

これは実際に仮想関数とは関係ありません。 Valgrindのの検出がある 三配分:main

  1. new CClass
  2. mallocAClassコンストラクタ。
  3. mallocCClass::Init。コールがバランスされていない理由として

:あなたはAClassコンストラクタでalloc'dだstrをリークしている - あなたはCClass::Initstrポインタを変更している:

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

最初以前に解放せず割り当てられたバッファ。

+0

明示的に3つのallocsをリストアップしていただきありがとうございます。私はValgrindのコマンドラインスイッチを使ってそのことを分かったかもしれないと思うが、それをどう解釈するかはまだ分かっている。 –

2

AClassはデフォルトコンストラクタは、この行があります:あなたのInitで

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

をあなたはこの

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

第三のalloc(と自由秒)を行うときに、あなたはそれを失う新しく、削除Cクラスの