我看到在c++中有多种方法来分配和释放数据,我明白,当你调用malloc时你应该叫自由,当你使用新的操作符应与删除和对它是错误的把两个调用free()(例如,创建新的操作符),但是我不清楚我应该使用malloc / free,当我在现实世界中应该使用新的/删除程序。

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


当前回答

在下面的场景中,我们不能使用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;
    }
};

其他回答

在下面的场景中,我们不能使用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;
    }
};

如果你处理的数据不需要构造/销毁,需要重新分配(例如,一个大的整数数组),那么我相信malloc/free是一个很好的选择,因为它给你realloc,这比new-memcpy-delete快得多(它在我的Linux盒子上,但我猜这可能是平台相关的)。如果你使用的c++对象不是POD并且需要构造/销毁,那么你必须使用new和delete操作符。

无论如何,如果可以利用realloc可以给您的速度提升(如果您正在重新分配大型POD数组,有时是一个显著的提升),我不明白为什么不应该同时使用这两种方法(前提是您释放了错误的内存并删除了用new分配的对象)。

除非你需要它,否则你应该坚持在c++中使用new/delete。

我以前玩过很少的计算机图形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函数确实会慢一些。 但是在赋值之前,所有的bit必须先设置为0。 因为数组的值可以有任意的内容。

假设,数组被分配给另一个较小的数组。 数组元素的一部分仍然可以有任意内容。 在这种情况下,建议调用memset函数。

memset((void*)pWord, 0, sizeof(pWord) / sizeof(char)); 

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

new和delete关键字实际上是一些定义好的C操作符。 也许一个自定义联合或类可以定义这些操作符。 如果在类中没有定义new和delete,则它们可能不起作用。 但如果一个类是由另一个类派生的,这个类有这些操作符, new和delete关键字可以具有基本的类行为。

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

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

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

当必须删除一个数组时,使用delete[]操作符:

delete[] pWord; 

类型转换并不坏,只是不适用于所有的变量类型。 转换类型转换也是一个必须定义的运算符函数。 如果没有为某个类型定义此操作符,则它可能不起作用。 但并不是所有的错误都是由这个转换强制转换操作符引起的。

另外,在使用自由调用时,必须使用到空指针的类型转换。 这是因为free函数的实参是一个空指针。

free((void*)pWord); 

可能会出现一些错误,因为数组的大小太小。 但这是另一个故事,并不是因为使用了演员阵容。

致以亲切的问候,艾德里安·布里纳斯

要回答您的问题,您应该知道malloc和new之间的区别。区别很简单:

malloc分配内存,而new分配内存并调用要分配内存的对象的构造函数。

因此,除非仅限于使用C,否则永远不要使用malloc,特别是在处理c++对象时。这将会破坏你的程序。

free和delete的区别也是一样的。不同之处在于,delete除了释放内存外,还会调用对象的析构函数。

简短的回答是:如果没有真正好的理由,不要在c++中使用malloc。malloc在与c++一起使用时有许多缺陷,而new定义是为了克服这些缺陷。

c++代码中新修正的缺陷

malloc is not typesafe in any meaningful way. In C++ you are required to cast the return from void*. This potentially introduces a lot of problems: #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 } It's worse than that though. If the type in question is POD (plain old data) then you can semi-sensibly use malloc to allocate memory for it, as f2 does in the first example. It's not so obvious though if a type is POD. The fact that it's possible for a given type to change from POD to non-POD with no resulting compiler error and potentially very hard to debug problems is a significant factor. For example if someone (possibly another programmer, during maintenance, much later on were to make a change that caused foo to no longer be POD then no obvious error would appear at compile time as you'd hope, e.g.: struct foo { double d[5]; virtual ~foo() { } }; would make the malloc of f2 also become bad, without any obvious diagnostics. The example here is trivial, but it's possible to accidentally introduce non-PODness much further away (e.g. in a base class, by adding a non-POD member). If you have C++11/boost you can use is_pod to check that this assumption is correct and produce an error if it's not: #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))); } Although boost is unable to determine if a type is POD without C++11 or some other compiler extensions. malloc returns NULL if allocation fails. new will throw std::bad_alloc. The behaviour of later using a NULL pointer is undefined. An exception has clean semantics when it is thrown and it is thrown from the source of the error. Wrapping malloc with an appropriate test at every call seems tedious and error prone. (You only have to forget once to undo all that good work). An exception can be allowed to propagate to a level where a caller is able to sensibly process it, where as NULL is much harder to pass back meaningfully. We could extend our safe_foo_malloc function to throw an exception or exit the program or call some handler: #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; } Fundamentally malloc is a C feature and new is a C++ feature. As a result malloc does not play nicely with constructors, it only looks at allocating a chunk of bytes. We could extend our safe_foo_malloc further to use placement 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(); } Our safe_foo_malloc function isn't very generic - ideally we'd want something that can handle any type, not just foo. We can achieve this with templates and variadic templates for non-default constructors: #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)...); } }; Now though in fixing all the issues we identified so far we've practically reinvented the default new operator. If you're going to use malloc and placement new then you might as well just use new to begin with!