什么是C ++中的动态内存分配?

时间:2013-01-29 02:17:20

标签: c++ memory-management malloc new-operator dynamic-allocation

我正在学习C ++中的动态内存分配,并提到了关键字newnew[]。 据说,用户可以在运行时指定内存分配的大小,而不像在源代码中声明一个具有固定大小的变量或数组。

我不明白这个概念。它是如何工作的?我只需要澄清这个想法,一个例子会有所帮助!

2 个答案:

答案 0 :(得分:9)

所以,如果你想要一个包含10个整数的数组,你就会写:

int arr[10]; 

但是如果你想做这样的事情呢?

cout << "How many?";
cin >> num;

int arr[num];

嗯,C ++语言不允许这样做。相反,你必须这样做:

int *arr = new int[num]; 

创建你的数组。后来你必须[1]使用:

delete [] arr; 

释放记忆。

那么,这是如何工作的?当你调用new时,C ++运行时库[你不必编写构成C ++基础的代码]将计算出num整数占用多少空间,并在内存中找到一些空间那。我不会详细介绍“你如何找到记忆”。现在,只要相信我,就可以在某处使用一些内存来存储一些整数。

当您稍后调用delete时,相同的内存将被返回到它来自的“池”或“堆”内存中。

当然,如果你的机器有256 MB内存,并且你试图要求空间来存储2.5亿个整数,请记住整数占用超过一个字节,它不会锻炼 - 这里没有“神奇” - 内存仍然限制在机器中可用的数量....你只是有权在程序中确定它何时运行,你需要多少内存,而不是而不是必须决定何时编写程序。

编辑:通常最好使用已经存在的“容器 - ”和“包装类”来“隐藏”任何内存分配,这对于此目的非常有用。例如:

 std::vector<int> arr;

可以作为整数的变量存储,你永远不必担心释放内存,甚至在你将内存存储之前知道你需要多少内存。

 std::shared_ptr<int> arr = new int[num]; 

是另一种情况,当“shared_ptr”不再使用时[它跟踪共享指针类中的内容,所以你永远不需要关心释放内存]。

[1]如果你不想泄漏内存,那么泄漏内存就是“坏风格”。如果你这样做,不会让任何人高兴。

答案 1 :(得分:4)

我在C ++中看过很多关于内存分配的帖子,关于&#34;新运算符&#34; vs&#34; operator new&#34;,关于new int(100) vs new int[100]的问题,关于内存初始化的问题......我认为应该有一个答案可以一劳永逸地总结一切,我和#39;我选择这个问题来撰写本摘要。它是关于动态内存分配,在运行时堆上的分配。我还提供summary implementation(公共领域)。


C vs C ++

动态内存分配的主要功能:

  • 在C(标题<cstdlib>)中,我们主要有malloccalloc以及free。我不会谈论realloc
  • 在C ++(标题<new>)中,我们有:
    • 带有初始化参数的模板单对象分配:
      • new T( args )
      • new (std::nothrow) T( args )
      • delete ( T* )
    • 使用默认初始化的模板多对象分配:
      • new T[ size_t ]
      • new (std::nothrow) T[ size_t ]
      • delete[] ( T* )
    • 模板内存初始化,不分配单个或多个对象:
      • new (void*) T( args )
      • new (void*) T[ size_t ]
    • 内部新表达式
      • 原始内存分配::operator new( size_t );
      • 原始内存分配无例外::operator new( size_t, std::nothrow );
      • 未分配::operator new( size_t, ptr )的原始内存初始化。

请查看this post进行简明比较。


旧版C动态分配

要点 :完成类型擦除(void*指针),因此无构造/销毁,指定的大小字节(通常使用sizeof)。

malloc( size_t )根本没有初始化内存(原始内存包含垃圾,在使用前总是手动初始化)。 calloc( size_t, size_t )将所有位初始化为0(略微开销,但对POD数字类型有用)。应使用free 释放任何已分配的内存。

在内存释放之前使用/ 之前,的构建/销毁应该手动完成


C ++动态分配

要点 :由于类似语法执行不同的操作而导致混淆,所有 delete - 语句调用析构函数,所有 delete - 语句采用完全类型的指针,一些 new - 语句返回完全类型的指针,一些 {{1 - 语句调用一些构造函数。

警告 :正如您将在下面看到的那样,new可以是关键字功能。最好不要谈论&#34;新的运营商&#34;和/或&#34;运营商新&#34;为了avoid confusions。我打电话给#34; new - 陈述&#34;包含new作为函数或关键字的任何有效语句。人们还谈论&#34; new - 表达式&#34;,其中new是关键字而不是函数。

原始内存分配(无初始化)

不要自己使用。这是由 new-expressions 在内部使用的(见下文)。

这些分配初始化内存,特别是调用已分配对象的默认构造函数。因此,在使用Tdelete发布分配之前,必须手动初始化所​​有元素

注意 :我没有足够的压力,你不应该自己使用它。但是,如果您应该使用它,请确保在此类分配上调用delete[]void时(通常在手动初始化之后),将指针传递给delete而不是类型指针。我亲身经历过非POD类型的运行时错误和一些编译器(可能是我的错误)。

原始内存初始化(无分配)

不要自己使用。这是由 new-expressions 在内部使用的(见下文)。 在下文中,我假设某些类型delete[]和大小void *ptr = ::operator new( n*sizeof(T) )T

然后n使用默认构造函数::operator new( n*sizeof(T), (T*) ptr )n开始初始化T类型ptr元素。这里有 no allocation ,只使用default-constructor进行初始化。

单一对象分配&amp;初始化

  • T::T()使用构造函数new T( args )为<{1}}类型的单个对象分配初始化内存。除非省略参数(即T或甚至T::T( args )),否则不会将默认构造函数称为。失败时引发异常new T()
  • new T相同,只是在失败时返回std::bad_alloc
  • 使用new (std::nothrow) T( args )调用析构函数NULL并释放相应的内存。

多个对象分配&amp;初始化

  • delete使用默认构造函数为<{1}}类型的T::~T()对象分配初始化内存。失败时引发异常new T[n]
  • n的同意,除非在失败的情况下返回T
  • 使用std::bad_alloc为每个元素调用析构函数new (std::nothrow) T[n] 并释放相应的内存。

内存初始化(又名&#34;放置新&#34;)

这里没有分配。无论分配方式如何:

  • NULLdelete[]存储的内存上调用构造函数T::~T()。除非省略参数,否则不会调用默认构造函数。
  • new (ptr) T(args)调用从T::T(args)ptr存储的new (ptr) T[n]T::T()对象的默认构造函数n(即{{1} }} bytes。。

相关帖子