2011-06-10 292 views
5

我正在实现一个二进制堆类。堆被实现为动态分配的数组。堆类有成员的身份,大小和一个指向数组的指针,如:构造函数中的malloc

class Heap 
{ 
    private: 
     Heap* H; 
     int capacity; //Size of the array. 
     int size; //Number of elements currently in the array 
     ElementType* Elements; //Pointer to the array of size (capacity+1) 

     //I've omitted the rest of the class. 
}; 

我construcor看起来是这样的:

Heap::Heap (int maxElements) 
{ 
    H = (Heap*) malloc (sizeof (Heap)); 
    H -> Elements = (ElementType*) malloc ((maxElements+1)*sizeof (ElementType)); 
    H -> Elements[0] = DUMMY_VALUE; //Dummy value 
    H -> capacity = maxElements; 
    H -> size = 0; 
} 

由于我mallocing两次,并在构造函数中提领两个指针,我应该检查它是否成功。但如果失败了,我该怎么办?构造函数本身不能返回任何东西来表明它失败。完全避免构造函数中的malloc是不错的编程习惯吗?

+2

你好,@Sahil!欢迎来到Stack Overflow。感谢您粘贴与您的问题相关的代码,但请在提出下一个问题时将其格式化为代码(每行缩进四个空格,或使用标有'{}'的按钮)。另外,我不认为你需要你的'H'成员变量。当你的构造函数被输入时,'Heap'对象的空间已经被分配了。你只需要为'Elements'数组分配空间。 – 2011-06-10 19:36:36

+0

我不明白为什么你的Heap对象有一个指向另一个Heap对象的指针,特别是当你不使用你正在构造的对象的成员时。我会失去第一个'malloc'并直接使用你的对象的成员。 – 2011-06-10 19:39:43

+0

事实上,让指针“H”指向构造函数没有运行的内存是非常糟糕的做法。我敢打赌,解引用'H'调用未定义的行为。为什么不直接在你的课堂上储存'capacity','size'和'Elements'? – Vlad 2011-06-10 19:41:14

回答

14

首先,你需要你Heap对象内Heap*成员变量,你当然不应该为它在Heap构造函数分配内存 - 这只是自找麻烦。您也不应该以H->Elements访问您的成员变量,而应该简单地访问Elements

您需要分配的唯一东西是Elements数组。

关于处理分配失败,构造函数应通过异常指示失败。甚至有一个标准的异常类型,std::bad_alloc通常用于指示分配内存失败。

例如:

#include <stdexcept> // for std::bad_alloc 
... 
Heap::Heap (int maxElements) 
{ 
    Elements = (ElementType*) malloc ((maxElements+1)*sizeof (ElementType)); 
    if (Elements == NULL) 
     throw std::bad_alloc("Failed to allocate memory"); 
    ... 
} 

更妙的是,使用new而不是malloc分配内存。如果分配内存失败,new将自动抛出类型为std::bad_alloc的异常。

例子:

Heap::Heap (int maxElements) 
{ 
    Elements = new ElementType[maxElements + 1]; // throws std::bad_alloc on failure 
    ... 
} 

注:如果您使用new分配对象,则必须使用delete来释放它,而不是free。 (更正:在上面的示例中,您使用的是新的阵列形式,new[],因此您应该调用删除的阵列形式,delete[])。

最后,你有没有看到如何ElementType声明,但如果它是具有非默认构造函数/析构型(或者如果它,这意味着它有可能成为这种类型的模板参数),你使用new而不是malloc分配它时,因为malloc将不会调用构造函数(和free将不会调用析构函数)。一般来说,最好总是在C++中使用newdelete,而不是mallocfree

+0

@Roddy但它不是'new heap',它是'Heap * H =(Heap *)malloc(sizeof(Heap))' - 构造函数不会被调用;-) – 2011-06-10 19:46:53

+1

如果使用'new [] ',不要使用'delete' - 使用'delete []'! – 2011-06-10 19:49:07

+0

@Khaled:Roddy在评论我最初推荐用'H = new Heap'替换'H =(堆*)malloc(sizeof(堆))'的答案。那是在我意识到这是多么错误之前... – HighCommander4 2011-06-10 19:50:05

1

你是在自己的构造函数中分配对象吗?无厘头:

H = (Heap*) malloc (sizeof (Heap)); 

构造是由new操作者调用,内​​存分配之后。如果你想创建一个单 - 使用方法,实例化对象的静态方法,并调用

class Heap{ 
public: 
    static Heap* Get(); 
private: 
    Heap(); 
    static Heap* H; 
} 

Heap *Heap::H = 0; 

Heap * Heap::Get() 
{ 
    if (!H) 
     H = new (Heap); 
    return H; 
} 

Heap::Heap() 
{ 
    // whatever else 
} 

你的问题:malloc是一个C函数。在C++中 - 使用new。你不需要检查返回值,那么,new将在失败时引发异常。

+1

是的,这一点没有意义。但这不是他的问题的答案,只是你的一个有用的观察。也许这应该是一个评论而不是答案? – 2011-06-10 19:37:41

5

你应该学习,其中第一个就是一些基本的C++“道路规则”:

使用标准模板库!

class Heap { 
    private: 
    std::vector<ElementType> elements; 
} 

而你的构造函数?你不需要一个。

一般来说,任何在C++中使用malloc()free()都是'代码异味'。这是一个确定的方式,结束了错误构造的对象,缓冲区溢出和内存泄漏。使用newdelete,最好使用智能指针。

或者更好。只要可能就让你的对象静态构造。