【问题标题】:Malloc in constructors构造函数中的 Malloc
【发布时间】:2011-09-12 18:19:18
【问题描述】:

我正在实现一个二进制堆类。堆被实现为一个动态分配的数组。堆类具有成员容量、大小和指向数组的指针,如:

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.
};

我的构造函数如下所示:

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;  
}

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

【问题讨论】:

  • 你好,@Sahil!欢迎来到堆栈溢出。感谢您粘贴与您的问题相关的代码,但请在您提出下一个问题时将其格式化为代码(每行缩进四个空格,或使用标有{} 的按钮)。另外,我认为您根本不需要 H 成员变量。 Heap 对象的空间在输入构造函数时已经分配。您只需要为Elements 数组分配空间。
  • 我不明白为什么你的 Heap 对象里面有一个指向另一个 Heap 对象的指针,尤其是当你不使用你正在构建的对象的成员时。我会丢失第一个 malloc 并直接使用您的对象的成员。
  • 实际上,让指针H 指向没有运行构造函数的内存是非常糟糕的做法。我敢打赌,取消引用 H 会调用未定义的行为。为什么不直接在课堂上存储capacitysizeElements
  • 在 C++ 代码中避免malloc 是一种很好的编程习惯,而不仅仅是构造函数。搜索 RAII 和 operator new,然后研究智能指针,以获得首选的 C++ 内存管理方法。
  • 在内部使用向量。

标签: c++ class constructor malloc oop


【解决方案1】:

首先,您确实不需要在您的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的数组形式new[],所以你应该调用delete的数组形式delete[]

最后,您还没有展示ElementType 是如何声明的,但是如果它是一个具有非默认构造函数/析构函数的类型(或者如果它是一个模板参数,这意味着它可能是这种类型),那么您必须在分配它时使用new 而不是malloc,因为malloc 不会调用构造函数(而free 不会调用析构函数)。一般来说,在 C++ 中始终使用 newdelete 而不是 mallocfree 是一种很好的做法。

【讨论】:

  • @Roddy 但不是new Heap,而是Heap * H = (Heap*)malloc(sizeof(Heap)) - 不会调用构造函数;-)
  • 如果你使用new[],不要使用delete -- 使用delete[]
  • @Khaled:Roddy 正在评论我最初建议用 H = new Heap 替换 H = (Heap*)malloc(sizeof(Heap)) 的答案。那是在我意识到这是多么错误之前......
【解决方案2】:

您是在自己的构造函数中分配对象吗?没有意义:

    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 会在失败时抛出异常。

【讨论】:

  • 是的,那一点没有意义。但这不是他问题的答案,只是您的有用观察。也许这应该是评论而不是答案?
【解决方案3】:

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

使用标准模板库!

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

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

一般来说,在 C++ 中对malloc()free() 的任何使用都是“代码异味”。这是一种以错误构造的对象、缓冲区溢出和内存泄漏而告终的可靠方法。使用newdelete,最好使用智能指针。

或者,更好。尽可能让你的对象静态构造。

【讨论】:

    猜你喜欢
    • 2011-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-30
    • 2021-01-03
    • 1970-01-01
    • 2015-05-21
    相关资源
    最近更新 更多