我在哪些情况下使用malloc vs new?
我在C ++中看到有多种分配和释放数据的方法,我知道当你调用malloc
时应该free
调用,当你使用new
操作符时,你应该配对delete
,混合两者是错误的(例如,Calling free()
用new
操作符创建的东西),但我不清楚什么时候应该使用malloc
/ free
,何时应该在我的真实世界程序中使用new
/ delete
。
如果您是C ++专家,请告诉我您在这方面遵循的任何规则或惯例。
除非你被迫使用C,否则不应该使用 malloc
。 始终使用new
。
如果您需要大量数据,请执行以下操作:
char *pBuffer = new char[1024];
请注意,虽然这是不正确的:
//This is incorrect - may delete only one element, may corrupt the heap, or worse...
delete pBuffer;
相反,您应该在删除数据数组时执行此操作:
//This deletes all items in the array
delete[] pBuffer;
new
关键字是C ++的方法,它会确保你的类型的构造函数被调用 。 new
关键字也更安全,而malloc
根本不是类型安全的。
如果您需要更改数据缓冲区的大小,唯一可以考虑的方法是使用malloc
有利。 new
关键字没有类似realloc
。 realloc
函数可能能够更有效地扩展一块内存的大小。
值得一提的是,你不能混用new
/ free
和malloc
/ delete
。
注意:这个问题中的一些答案是无效的。
int* p_scalar = new int(5); // Does not create 5 elements, but initializes to 5
int* p_array = new int[5]; // Creates 5 elements
简短的答案是:不要使用malloc
for C ++,但没有充分的理由这么做。 malloc
具有许多不足之处与C ++,它用来当new
定义来克服。
新的C ++代码修复了缺陷
malloc
不是以任何有意义的方式安全的。 在C ++中,你需要从void*
返回。 这可能会带来很多问题:
#include <stdlib.h>
struct foo {
double d[5];
};
int main() {
foo *f1 = malloc(1); // error, no cast
foo *f2 = static_cast<foo*>(malloc(sizeof(foo)));
foo *f3 = static_cast<foo*>(malloc(1)); // No error, bad
}
但比这还糟糕。 如果所讨论的类型是POD(普通的旧数据),那么你可以半理性地使用malloc
来为它分配内存,就像第一个例子中的f2
那样。
如果某种类型是POD,它并不是那么明显。 事实上,给定类型可能会从POD更改为非POD,而不会导致编译器错误,并且可能很难调试问题,这是一个重要因素。 例如,如果有人(可能是另一位程序员,在维护期间,很多时候会做出更改,导致foo
不再是POD,那么编译时就不会出现明显的错误,例如:
struct foo {
double d[5];
virtual ~foo() { }
};
会使f2
的malloc
也变得不好,没有任何明显的诊断。 这里的示例很简单,但可能会意外地将非POD引入更远的地方(例如,在基类中,通过添加非POD成员)。 如果你有C ++ 11 / boost,你可以使用is_pod
来检查这个假设是否正确,如果不是:
#include <type_traits>
#include <stdlib.h>
foo *safe_foo_malloc() {
static_assert(std::is_pod<foo>::value, "foo must be POD");
return static_cast<foo*>(malloc(sizeof(foo)));
}
虽然boost不能确定一个类型是否是没有C ++ 11或其他编译器扩展的POD。
如果分配失败, malloc
返回NULL
。 new
会抛出std::bad_alloc
。 稍后使用NULL
指针的行为是未定义的。 抛出异常时具有干净的语义,并且从错误源抛出异常。 在每次调用时用适当的测试对malloc
进行包装看起来很乏味且容易出错。 (你只需要忘记一次就可以撤消所有的好工作)。 可以允许异常传播到调用者能够合理地处理它的级别,其中NULL
非常难以有效回传。 我们可以扩展safe_foo_malloc
函数来引发异常或退出程序或调用一些处理程序:
#include <type_traits>
#include <stdlib.h>
void my_malloc_failed_handler();
foo *safe_foo_malloc() {
static_assert(std::is_pod<foo>::value, "foo must be POD");
foo *mem = static_cast<foo*>(malloc(sizeof(foo)));
if (!mem) {
my_malloc_failed_handler();
// or throw ...
}
return mem;
}
从根本上讲, malloc
是C特性, new
特性是C ++特性。 因此, malloc
不能很好地与构造函数一起玩,它只会分配一大块字节。 我们可以进一步扩展我们的safe_foo_malloc
以使用new
展示位置:
#include <stdlib.h>
#include <new>
void my_malloc_failed_handler();
foo *safe_foo_malloc() {
void *mem = malloc(sizeof(foo));
if (!mem) {
my_malloc_failed_handler();
// or throw ...
}
return new (mem)foo();
}
我们的safe_foo_malloc
函数不是非常通用的 - 理想情况下,我们希望能够处理任何类型的东西,而不仅仅是foo
。 我们可以通过模板和可变参数模板来实现非默认构造函数:
#include <functional>
#include <new>
#include <stdlib.h>
void my_malloc_failed_handler();
template <typename T>
struct alloc {
template <typename ...Args>
static T *safe_malloc(Args&&... args) {
void *mem = malloc(sizeof(T));
if (!mem) {
my_malloc_failed_handler();
// or throw ...
}
return new (mem)T(std::forward(args)...);
}
};
现在,虽然在修复迄今为止我们确定的所有问题,但我们实际上已经重新设计了默认的new
运算符。 如果你打算使用malloc
和placement new
那么你可以使用new
来开始!
从C ++ FQA Lite开始:
[16.4]为什么我应该使用new而不是可靠的旧malloc()?
FAQ:new / delete调用构造函数/析构函数; 新是类型安全的,malloc不是; 新的可以被一个类覆盖。
FQA:FAQ提到的新特性不是美德,因为构造函数,析构函数和运算符重载都是垃圾(看看没有垃圾回收会发生什么?),类型安全问题在这里非常小(通常你有将malloc返回的void *转换为正确的指针类型,将其分配给一个类型化的指针变量,这可能很烦人,但远非“不安全”)。
哦,并且使用可靠的旧malloc可以使用同样值得信赖和旧的realloc。 太糟糕了,我们没有一个闪亮的新运营商更新或什么。
尽管如此,即使语言是C ++,new也不足以证明与一种语言使用的通用风格的偏差。 特别是,如果你只是简单地使用malloc对象,那么带有不平凡构造函数的类将会以致命的方式行事不端。 那么为什么不在整个代码中使用新的? 人们很少重载运营商新的,所以它可能不会太多。 如果他们超载新的,你总是可以让他们停下来。
对不起,我无法抗拒。 :)
链接地址: http://www.djcxy.com/p/2211.html