何时使用malloc和/或new?

595

C++有多种分配和释放数据的方式。我知道使用malloc时应该用free来释放内存,而使用new操作符时应该与delete搭配使用。如果混合使用这两种方法(例如调用free()释放由new操作符创建的对象),那么将是一个错误。但是在实际编程中,我不清楚什么情况下应该使用malloc/free以及何时应该使用new/delete

如果您是C++专家,请告诉我在这方面遵循的任何经验法则或惯例。


43
我想提醒一下,您不能混合使用两种风格——也就是说,您不能使用new创建一个对象,然后调用free()释放它,也不能尝试删除由malloc()分配的块。这可能很显而易见,但还是要注意一下... - nsayer
46
好的回答,我要补充一点(我之前没看到的)是,new/delete会自动调用构造函数/析构函数,而malloc/free则不会。这是一个值得提及的区别。 - Bill K
3
对于现代C++,我仍在寻找使用它们的理由。 - Rahly
或者使用std:shared_ptr<T>,这样你就不必删除了。 - Vincent
1
std::unique_ptr<T> 应该是默认选择,而不是 std::shared_ptr<T>。 - avernus
20个回答

6
如果你处理的是不需要构造和销毁,并且不需要重新分配空间的数据(例如,大型整数数组),那么我认为malloc/free是一个很好的选择,因为它提供了realloc,这比new-memcpy-delete要快得多(在我的Linux系统上是这样的,但我猜这可能取决于平台)。如果你处理的是不是POD类型并需要构造/析构的C++对象,则必须使用new和delete运算符。
无论如何,如果你能利用realloc带来的速度提升(有时候是显著的,如果你正在重新分配大型的POD数组),那么你应该同时使用它们(只要你释放了malloc的内存并删除了使用new分配的对象)。但在C++中,除非需要使用它,否则应该坚持使用new/delete。

6
如果您使用的是C++,请尝试使用new/delete而不是malloc/calloc,因为它们是运算符。对于malloc/calloc,您需要包含另一个头文件。不要在同一代码中混合两种不同的语言。它们的工作方式非常相似,都从哈希表中动态地分配内存。

4

new会初始化结构体的默认值,并正确地将其内部引用链接到自身。

例如:

struct test_s {
    int some_strange_name = 1;
    int &easy = some_strange_name;
}

因此,new struct test_s将返回一个带有工作引用的初始化结构,而malloc的版本没有默认值,内部引用未初始化。


3
如果你有C代码需要移植到C++,可以将其中的任何malloc()调用保留下来。对于任何新的C++代码,建议使用new代替。

3

从较低的角度来看,new在提供内存之前会初始化所有内存,而malloc会保留内存的原始内容。


4
通常情况下,使用new不会初始化内存,但有方法可以实现这一点:请参见https://dev59.com/zHE95IYBdhLWcg3wrP6w,了解其中一个讨论。 - wjl

2
考虑使用malloc/free而不是new/delete的罕见情况是在分配和重新分配(简单的pod类型,而不是对象)时使用realloc,因为在C++中没有类似于realloc的函数(尽管可以使用更多的C++方法来实现)。

2
在下面的情况中,我们不能使用new,因为它会调用构造函数。
class  B  {
private:
    B *ptr;
    int x;
public:
    B(int n)  {
        cout<<"B: ctr"<<endl;
        //ptr = new B;  //keep calling ctr, result is segmentation fault
        ptr = (B *)malloc(sizeof(B));
        x = n;
        ptr->x = n + 10;
    }
    ~B()  {
        //delete ptr;
        free(ptr);
        cout<<"B: dtr"<<endl;
    }
};

1

我曾经接触过一些用于计算机图形学的C/C++应用程序。 经过这么长时间,有些东西已经消失了,我非常想念它们。

问题在于,malloc和new,free和delete都可以一起使用,尤其是对于某些基本类型而言,这是最常见的情况。

例如,char数组既可以用malloc分配,也可以用new分配。 主要的区别是,用new可以实例化一个固定大小的数组。

char* pWord = new char[5]; // allocation of char array of fixed size 

在这种情况下,您不能使用变量作为数组的大小。 相反,malloc函数可以允许可变大小。

int size = 5; 
char* pWord = (char*)malloc(size); 

在这种情况下,可能需要使用转换强制运算符。 对于从malloc返回的类型,它是一个指向void而不是char的指针。 有时编译器可能不知道如何转换此类型。
在分配内存块后,您可以设置变量值。 对于一些更大的数组,memset函数可能确实较慢。 但是,在分配值之前必须先将所有位设置为0,因为数组的值可能具有任意内容。
假设将数组分配给另一个较小尺寸的数组。 部分数组元素仍然可能具有任意内容。 在这种情况下,推荐调用memset函数。
memset((void*)pWord, 0, sizeof(pWord) / sizeof(char)); 

分配函数适用于所有C包。因此,这些是通用函数,必须适用于更多的C类型。而C++库是旧的C库的扩展。因此,malloc函数返回一个通用的void*指针。结构体没有定义新的或删除操作符。在这种情况下,可以使用malloc分配自定义变量。

new和delete关键字实际上是一些定义好的C运算符。也许一个自定义的联合或类可以定义这些运算符。如果在一个类中没有定义new和delete,则可能无法正常工作。但是如果一个类派生自另一个具有这些运算符的类,则new和delete关键字可以具有基本类行为。

关于释放数组,free只能与malloc成对使用。不能使用malloc分配变量,然后使用delete释放。

简单的delete操作符只引用数组的第一个项目。因为pWord数组也可以写成:

pWord = &pWord[0]; // or *pWord = pWord[0]; 

当需要删除一个数组时,请使用delete[]运算符:

delete[] pWord; 

转换并不是坏的,只是对于所有变量类型都不适用。 转换转换也是一个运算符函数,必须定义。 如果这个运算符没有为某种类型定义,则可能无法工作。 但并非所有错误都是由于此转换转换运算符引起的。
当使用free调用时,还必须使用指向void的指针进行转换。 这是因为free函数的参数是一个void指针。
free((void*)pWord); 

一些错误可能会出现,因为数组的大小太小。 但这是另外一个故事,不是由于使用转换而引起的。
顺祝商祺,Adrian Brinas

0

newdelete 运算符可以用于类和结构体,而 mallocfree 只能用于需要转换的内存块。

使用 new/delete 将有助于改善您的代码,因为您不需要将分配的内存强制转换为所需的数据结构。


-4

在C语言中,malloc()用于动态分配内存,而在C++中则使用new()完成相同的工作。 因此,您不能混合使用这两种语言的编码约定。 如果您想了解calloc和malloc()之间的区别,那就更好了。


2
在C++中,您可以(但几乎总是不应该)使用malloc - interjay
1
你还错过了一个重要的点,即除非通过智能指针进行动态内存分配,否则应该尽量避免使用动态内存分配。否则你只是在为自己带来痛苦。 - thecoshman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接