在什么情况下使用 malloc 和/或 new?

In what cases do I use malloc and/or new?

提问人: 提问时间:10/9/2008 最后编辑:JVApen 更新时间:8/11/2022 访问量:354531

问:

我看到在 C++ 中有多种方法可以分配和释放数据,我知道当你调用时,你应该调用,当你使用你应该配对的运算符时,将两者混合在一起是错误的(例如调用使用运算符创建的东西),但我不清楚何时应该使用 / 以及何时应该在我的现实世界程序中使用 /。mallocfreenewdeletefree()newmallocfreenewdelete

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

C++ 内存管理 malloc new-operator

评论

46赞 Bill K 10/9/2008
好的答案,我所要补充的(我没有看到的)是 new/delete 为您调用构造函数/析构函数,malloc/free 不会。只是一个值得一提的差异。
43赞 nsayer 10/9/2008
我只想提醒一下,您不能混合使用这两种样式 - 也就是说,您不能使用 new 创建一个对象,然后对其调用 free(),也不能尝试删除由 malloc() 分配的块。说出来可能很明显,但尽管如此......
3赞 Rahly 12/23/2017
对于现代 C++,我仍在尝试找到使用它们的理由。
0赞 Vincent 2/27/2018
或者两者都不使用,而是使用 std:shared_ptr<T>。那么你根本就不必删除。
1赞 avernus 6/23/2022
std::unique_ptr<T> 应该是默认选项,而不是 std::shared_ptr<T>。

答:

487赞 Brian R. Bondy 10/9/2008 #1

除非你被迫使用C,否则你永远不应该使用。始终使用 .mallocnew

如果你需要一大块数据,只需执行以下操作:

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;

关键字是 C++ 执行此操作的方式,它将确保您的类型将调用其构造函数。关键字也更类型安全,而根本不是类型安全的。newnewmalloc

我认为使用这种唯一有益的方法是,如果您需要更改数据缓冲区的大小。关键字没有类似的方式。该函数可能能够更有效地扩展内存块的大小。mallocnewreallocrealloc

值得一提的是,你不能混合 / 和 /。newfreemallocdelete

注意:本题中的某些答案无效。

int* p_scalar = new int(5);  // Does not create 5 elements, but initializes to 5
int* p_array  = new int[5];  // Creates 5 elements

评论

3赞 KPexEA 10/9/2008
关于在你应该调用 delete []foo 时调用 delete foo,一些编译器会自动为你修复这个问题,而不会泄漏,而另一些编译器只会删除第一个条目并泄漏。我在一些代码中有一些,valgrind 会为您找到它们。
41赞 Michael Burr 10/9/2008
如果不使用正确的删除,则结果未定义。这是不正确的。事实上,它可能会把事情的一部分做对或工作,有时只是盲目的运气。
10赞 korona 10/9/2008
@KPexEA:即使一些编译器可能会修复你的错误,但一开始就犯错误仍然是错误的:)在适当的情况下,始终使用 delete[]。
92赞 Ben Supnik 2/12/2010
“除非你被迫使用C语言,否则你永远不应该使用malloc。始终使用新的。为什么?这里的胜利是什么?对于对象,我们需要构造,但对于内存块,您清楚地记录了两种犯编码错误的方法(在 new 中更容易捕获 () 与 [],以及不太容易捕获不匹配数组与缩放器 new 和 delete)。对原始内存块使用 new/delete 的动机是什么?
4赞 supercat 2/19/2013
@DeadMG:如果要创建一个供异步 API 函数使用的数组,那不是比 ?如果使用 ,指针失效的唯一方式是通过显式,而分配给 的内存在向量调整大小或离开作用域时可能会失效。(请注意,在使用异步方法时,必须考虑到如果异步方法仍处于挂起状态,则可能无法调用;如果可能需要放弃异步操作,则可能必须安排通过回调删除)。new[]std::vectornew[]deletestd::vectornew[]delete
34赞 dmckee --- ex-moderator kitten 10/9/2008 #2

mallocfree 用于分配将由以 c 为中心的库和 API 管理的内存。对您控制的所有内容使用 newdelete(以及 [] 变体)。

评论

11赞 Dacav 8/14/2010
还要注意,写得好的 C 库会在内部隐藏 malloc 和 free,这就是 C 程序员应该如何工作。
0赞 milesma 7/31/2013
@dmckee,您有使用 malloc 和 free 的以 C 为中心的库C++示例吗?
3赞 supercat 4/7/2015
@Dacav:如果一个 C 函数将接受指向一个对象的指针,并且在函数返回后需要继续使用该对象,并且调用方无法知道何时仍然需要该对象,则该函数指定指针必须已使用 创建是完全合理的。同样,如果一个函数需要创建一个对象并将其返回给调用者,那么指定调用者必须在不再需要对象时调用该对象是完全合理的。这些函数如何避免向调用方公开其对 malloc/free 的使用?mallocstrdupfree
0赞 Dacav 4/7/2015
@supercat,让 C 函数接受指向对象的指针本身就存在一些错误,因为 C 根本不知道对象。一般来说,我认为最好的方法是在 C 语言中也使用围绕分配/释放的语义包装器。如果 C 库要求调用方预分配和/或取消分配内存,它仍然可以接受,但不太灵活。如果 C 函数正在执行此操作并声明对已分配内存的所有权,则隐式要求使用 malloc 分配它。
1赞 autistic 4/30/2018
@Dacav 从C++标准中,引诱C++对象模型一节中,我们可以看到对象的定义:“对象是存储的区域。C 标准中也有类似的定义; 在 C 和 C++ 中,此变量表示对象。不同之处在于,C++ 中的一些(但不是全部)对象也是多态的(因为 C++ 毕竟是 OO)。不要错误地认为只有面向对象的代码才能使用对象。char c;
3赞 Fred Larson 10/9/2008 #3

如果你有 C 代码要移植到 C++,你可以在其中保留任何 malloc() 调用。对于任何新的 C++ 代码,我建议改用 new。

55赞 Ferruccio 10/9/2008 #4

始终在 C++ 中使用 new。如果你需要一个非类型化内存块,你可以直接使用运算符 new:

void *p = operator new(size);
   ...
operator delete(p);

评论

4赞 Greg Rogers 10/9/2008
有趣的是,当我需要这样的原始数据缓冲区时,我总是只分配一个无符号字符数组。
0赞 Brian R. Bondy 10/9/2008
注意语义应该是这样的:p_var = new type(initializer);不是大小。
13赞 Ferruccio 10/9/2008
如果直接调用运算符 new,则不会,则需要分配的字节数作为参数。
2赞 Brian R. Bondy 10/9/2008
Hrm 不确定,我从未听说过这种语法。
10赞 CB Bailey 10/9/2008
的反义词是 。调用类型为 的表达式不是一个定义明确的操作。operator newoperator deletedeletevoid*
59赞 Matthias Benkard 10/9/2008 #5

C++ FQA 精简版

[16.4] 为什么我应该使用 new 而不是 值得信赖的老 malloc()?

FAQ:新建/删除调用 构造函数/析构函数;new 是类型 安全,Malloc 不安全;新的可以是 被类覆盖。

FQA:新提到的优点 常见问题解答不是美德,因为 构造函数、析构函数和 运算符重载是垃圾(请参阅 当你没有垃圾时会发生什么 集合?)和类型安全 这里的问题真的很小(通常 你必须施放 malloc 到正确的指针类型 将其分配给类型化指针变量, 这可能很烦人,但远非如此 “不安全”)。

哦,使用值得信赖的旧 malloc 使得使用平等成为可能 值得信赖和老雷洛克。可惜我们 不要让闪亮的新操作员续约什么的。

不过,新的还不够糟糕 证明偏离共同点是合理的 在整个语言中使用的样式,甚至 当语言为 C++ 时。在 特别是,具有非平凡的类 构造函数在致命中会行为不端 如果您只是对对象进行恶意定位,则会采取各种方式。 那么为什么不在整个 法典?人们很少超载操作员 新的,所以它可能不会进入你的 太多了。如果他们确实超载 新的,你可以随时要求他们停下来。

对不起,我实在忍不住了。:)

评论

11赞 Miguel 11/27/2015
我不能认真对待这个评论,因为它清楚地表明了作者对 C++ 的偏见。C++ 是一种用于创建面向性能的软件的语言,垃圾收集器只会损害其目标。我不同意你的整个答案!
3赞 Dan Bechard 4/12/2016
@Miguel 你错过了这个笑话。
0赞 selwyn 10/9/2008 #6

and 运算符可以对类和结构进行操作,而 and 只能处理需要强制转换的内存块。newdeletemallocfree

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

3赞 Peiti Li 8/15/2011 #7

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

评论

4赞 wjl 9/30/2011
new 通常不会初始化内存,尽管有一些方法可以实现这一点:有关它的讨论,请参见 stackoverflow.com/questions/2204176/...
167赞 Flexo 11/2/2011 #8

简短的回答是:如果没有充分的理由,不要用于C++。 与 C++ 一起使用时有许多缺陷,这些缺陷被定义为克服。mallocmallocnew

新修复的 C++ 代码缺陷

  1. 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
    }
    
  2. 不过比这更糟糕。如果所讨论的类型是 POD(普通旧数据),那么您可以半明智地使用它来为其分配内存,就像在第一个示例中一样。mallocf2

    但是,如果类型是 POD,则不那么明显。给定类型有可能从 POD 更改为非 POD,而不会产生编译器错误,并且可能很难调试问题,这是一个重要因素。例如,如果有人(可能是另一个程序员,在维护期间,很久以后)进行更改,导致不再是 POD,那么编译时不会像您希望的那样出现明显的错误,例如:foo

    struct foo {
      double d[5];
      virtual ~foo() { }
    };
    

    会使 OF 也变得糟糕,没有任何明显的诊断。这里的示例很简单,但可能会意外地在更远的地方引入非 PODness(例如,在基类中,通过添加非 POD 成员)。如果你有 C++11/boost,你可以用它来检查这个假设是否正确,如果不是,则产生错误:mallocf2is_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。

  3. malloc如果分配失败,则返回。 会扔.以后使用指针的行为是未定义的。异常在引发时具有干净的语义,并且是从错误源引发的。在每次通话时都进行适当的测试似乎很乏味且容易出错。(你只需要忘记一次就可以撤消所有好的工作)。可以允许异常传播到调用方能够明智地处理它的级别,而在此级别上,要有意义地传回异常要困难得多。我们可以扩展我们的函数以抛出异常或退出程序或调用一些处理程序:NULLnewstd::bad_allocNULLmallocNULLsafe_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;
    }
    
  4. 从根本上说,它是一个 C 功能,并且是一个 C++ 功能。因此,它不能很好地与构造函数配合使用,它只考虑分配一个字节块。我们可以进一步扩展我们的使用放置:mallocnewmallocsafe_foo_mallocnew

    #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();
    }
    
  5. 我们的函数不是很通用 - 理想情况下,我们想要一些可以处理任何类型的东西,而不仅仅是 .我们可以使用非默认构造函数的模板和可变参数模板来实现这一点:safe_foo_mallocfoo

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

    现在,在修复我们迄今为止发现的所有问题时,我们实际上已经重新发明了默认运算符。如果你打算使用和放置,那么你不妨从一开始就使用!newmallocnewnew

评论

35赞 supercat 2/19/2013
太糟糕了,C++ 的制作和意思基本相同;我想知道为 POD 保留并可能假定所有类型都是非 POD 是否会有任何问题。在 C++ 发明之前由代码定义的任何类型都必然是 POD,所以我认为向后兼容性不会成为问题。将非 POD 类型声明为 而不是 THAN 有什么好处吗?structclassstructclassstructclass
1赞 Rakete1111 10/14/2018
@supercat 有点晚了,但事实证明,制作和做几乎相同的事情是一个很棒的设计决定,它现在启用了一个称为“元类”(来自 Herb)的简洁功能。structclass
0赞 supercat 10/14/2018
@Rakete1111:乍一看,该提案看起来像是预处理了使用美元前缀关键字(如 )的语言版本。然而,我不确定这与同义词有什么关系。$classclassstruct
0赞 Rakete1111 10/14/2018
@supercat 类型系统会分叉得更多。通过拥有和有效地表示相同的事物,您可以对它们()进行任意转换,而不必担心产生a,反之亦然。classstruct$classclassstruct
1赞 supercat 10/14/2018
@Rakete1111:如果某些类型的操作和转换对某些类型是安全的,而对其他类型则不安全,那么让类型直接标识它,并让编译器拒绝不安全的操作和转换,似乎比更改以仅适用于 POD 的方式使用的元类更好,静默更改为非 POD。
16赞 3 revsR. Martinho Fernandes #9

和 之间有一个很大的区别。 分配内存。这对 C 来说很好,因为在 C 中,内存块是一个对象。mallocnewmalloc

在 C++ 中,如果不处理 POD 类型(类似于 C 类型),则必须在内存位置调用构造函数才能实际拥有对象。非 POD 类型在 C++ 中非常常见,因为许多 C++ 功能使对象自动成为非 POD。

new分配内存并在该内存位置上创建一个对象。对于非 POD 类型,这意味着调用构造函数。

如果你做这样的事情:

non_pod_type* p = (non_pod_type*) malloc(sizeof *p);

您获取的指针不能被取消引用,因为它不指向对象。您需要先调用构造函数,然后才能使用它(这是使用 placement 完成的)。new

另一方面,如果您这样做:

non_pod_type* p = new non_pod_type();

你得到一个始终有效的指针,因为创建了一个对象。new

即使对于 POD 类型,两者之间也存在显着差异:

pod_type* p = (pod_type*) malloc(sizeof *p);
std::cout << p->foo;

这段代码将打印一个未指定的值,因为 创建的 POD 对象未初始化。malloc

使用 ,您可以指定要调用的构造函数,从而获得定义良好的值。new

pod_type* p = new pod_type();
std::cout << p->foo; // prints 0

如果确实需要它,可以使用 use 来获取未初始化的 POD 对象。有关更多信息,请参阅其他答案new

另一个区别是失败时的行为。当它无法分配内存时,返回一个空指针,同时抛出一个异常。mallocnew

前者要求您在使用之前测试返回的每个指针,而后者将始终生成有效的指针。

由于这些原因,在 C++ 代码中,您应该使用 ,而不是 .但即便如此,您也不应该使用“公开”,因为它会获取您以后需要发布的资源。使用时,应立即将其结果传递到资源管理类中:newmallocnewnew

std::unique_ptr<T> p = std::unique_ptr<T>(new T()); // this won't leak
-4赞 Hitesh Ahuja 7/26/2012 #10

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

评论

2赞 interjay 7/26/2012
你可以(但几乎总是不应该)在 C++ 中使用。malloc
1赞 thecoshman 10/11/2012
您还错过了避免动态内存分配的要点,除非通过智能指针这样做。你只是在为其他明智的痛苦设置自己
2赞 Barry 8/17/2012 #11

在以下场景中,我们不能使用 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;
    }
};
6赞 Petr Skocik 4/9/2013 #12

如果您使用不需要构造/销毁并且需要重新分配的数据(例如,大量 int),那么我相信 malloc/free 是一个不错的选择,因为它为您提供了 realloc,这比 new-memcpy-delete 快得多(它在我的 Linux 机器上,但我想这可能取决于平台)。如果使用非 POD 且需要构造/销毁的 C++ 对象,则必须使用 new 和 delete 运算符。

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

除非你需要它,否则你应该坚持在 C++ 中使用新建/删除。

7赞 herohuyongtao 1/15/2014 #13

有几件事是做不到的:newmalloc

  1. new通过调用该对象的构造函数来构造该对象
  2. new不需要对分配的内存进行类型转换。
  3. 它不需要分配一定数量的内存,而是需要一些 要构造的对象。

所以,如果你使用 ,那么你需要明确地做上面的事情,这并不总是实用的。此外,可以重载,但不能重载。mallocnewmalloc

6赞 user3488100 4/2/2014 #14

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

52赞 Yogeesh H T 11/26/2015 #15

新与 malloc()

1) 是运算符,while 是函数newmalloc()

2) 调用构造函数,而不调用。newmalloc()

3) 返回确切的数据类型,而返回 void *newmalloc()

4) 从不返回 NULL(失败时会抛出),而返回 NULLnewmalloc()

5) 重新分配 while can 未处理的内存newmalloc()

评论

13赞 Singh 10/7/2016
嗨,对于第 4 点),可以指示 new 在失败时返回 NULL。char* ptr = new (std::nothrow) char [323232];
2赞 Evan Moran 10/16/2016
6) new 从构造函数参数创建,而 malloc 使用 size。
1赞 Ma Ming 10/18/2017
还有一个功能new
1赞 autistic 4/30/2018
如果你在 C 中如此倾向于重新分配,我希望你会使用 而不是 ,并从初始化为 .另一方面,如果您想要在 C++ 中使用可调整大小的内存块,我建议而不是......那个或一个文件。reallocmallocNULLstd::vectorrealloc
4赞 kungfooman 12/14/2016 #16

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

例如

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

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

2赞 Florentino Tuason 7/29/2017 #17

考虑使用 malloc/free 而不是 new/delete 的极少数情况是使用 realloc 分配然后重新分配(简单的 pod 类型,而不是对象),因为 C++ 中没有与 realloc 类似的函数(尽管这可以使用更多的 C++ 方法完成)。

35赞 The Quantum Physicist 7/29/2017 #18

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

malloc 分配内存,同时分配内存并调用要为其分配内存的对象的构造函数。new

因此,除非您仅限于 C,否则永远不应该使用 malloc,尤其是在处理 C++ 对象时。这将是破坏程序的秘诀。

和之间的区别也完全相同。不同之处在于,除了释放内存之外,还会调用对象的析构函数。freedeletedelete

16赞 JVApen 12/23/2018 #19

仅当对象的生存期应与在其中创建对象的范围不同时,才需要动态分配(这也适用于使范围变小和变大),并且您有特定的原因,即按值存储它不起作用。

例如:

 std::vector<int> *createVector(); // Bad
 std::vector<int> createVector();  // Good

 auto v = new std::vector<int>(); // Bad
 auto result = calculate(/*optional output = */ v);
 auto v = std::vector<int>(); // Good
 auto result = calculate(/*optional output = */ &v);

从 C++11 开始,我们必须处理分配的内存,其中包含已分配内存的所有权。 是为必须共享所有权时而创建的。(你需要的比你在一个好的程序中预期的要少)std::unique_ptrstd::shared_ptr

创建实例变得非常容易:

auto instance = std::make_unique<Class>(/*args*/); // C++14
auto instance = std::unique_ptr<Class>(new Class(/*args*/)); // C++11
auto instance = std::make_unique<Class[]>(42); // C++14
auto instance = std::unique_ptr<Class[]>(new Class[](42)); // C++11

C++ 还添加了可以防止您需要内存分配的功能std::optional

auto optInstance = std::optional<Class>{};
if (condition)
    optInstance = Class{};

一旦“实例”超出范围,内存就会被清理。转让所有权也很容易:

 auto vector = std::vector<std::unique_ptr<Interface>>{};
 auto instance = std::make_unique<Class>();
 vector.push_back(std::move(instance)); // std::move -> transfer (most of the time)

那么你什么时候还需要呢?几乎从未从 C++11 开始。大多数情况下,您都会使用,直到您遇到通过原始指针转移所有权的 API。newstd::make_unique

 auto instance = std::make_unique<Class>();
 legacyFunction(instance.release()); // Ownership being transferred

 auto instance = std::unique_ptr<Class>{legacyFunction()}; // Ownership being captured in unique_ptr

在 C++98/03 中,您必须进行手动内存管理。如果是这种情况,请尝试升级到该标准的最新版本。如果你被卡住了:

 auto instance = new Class(); // Allocate memory
 delete instance;             // Deallocate
 auto instances = new Class[42](); // Allocate memory
 delete[] instances;               // Deallocate

确保正确跟踪所有权,以免出现任何内存泄漏!移动语义也不起作用。

那么,我们什么时候需要 C++ 中的 malloc?唯一有效的理由是分配内存,并在以后通过放置 new 对其进行初始化。

 auto instanceBlob = std::malloc(sizeof(Class)); // Allocate memory
 auto instance = new(instanceBlob)Class{}; // Initialize via constructor
 instance.~Class(); // Destroy via destructor
 std::free(instanceBlob); // Deallocate the memory

尽管上述内容是有效的,但这也可以通过新运算符来完成。 就是一个很好的例子。std::vector

最后,我们房间里还有大象:.如果你必须使用一个C库,其中内存在C++代码中分配,并在C代码中释放(或相反),你被迫使用malloc/free。C

如果您在这种情况下,请忘记虚函数、成员函数、类......只允许包含 POD 的结构。

规则的一些例外情况:

  • 您正在编写一个具有高级数据结构的标准库,其中 malloc 是合适的
  • 您必须分配大量内存(在 10GB 文件的内存副本中?
  • 你有工具阻止你使用某些构造
  • 您需要存储一个不完整的类型

评论

1赞 Russell Trahan 6/11/2022
绝对+1!New/delete 和 malloc/free 是为我们的祖父母准备的。这些不是在现代 C++ 中执行动态分配的建议方法。堆栈、unique_ptr和shared_ptr上的对象和容器是处理对象的“正确”方法。我有示例项目,其中有 100,000 行代码,带有 NO 或调用。mallocnew
1赞 Adrian 8/11/2022 #20

我以前玩过很少用于计算机图形学的 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* 指针。 这些 sructures 未定义 new 或 delete 运算符。 在这种情况下,可以使用 malloc 分配自定义变量。

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

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

简单的 delete 运算符仅引用数组的第一项。 因为 pWord 数组也可以写成:

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

当必须删除数组时,请改用 delete[] 运算符:

delete[] pWord; 

强制转换还不错,只是不适用于所有变量类型。 转换强制转换也是一个运算符函数,必须定义。 如果未为特定类型定义此运算符,则它可能无法正常工作。 但并非所有错误都是由于此转换转换运算符造成的。

此外,在使用免费调用时,必须使用对 void 指针的强制转换。 这是因为 free 函数的参数是一个 void 指针。

free((void*)pWord); 

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

亲切的问候, 阿德里安·布里纳斯