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

aan*_*nrv 4 c++ malloc memory-management new-operator dynamic-allocation

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

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

Mat*_*son 9

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

int arr[10]; 
Run Code Online (Sandbox Code Playgroud)

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

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

int arr[num];
Run Code Online (Sandbox Code Playgroud)

好吧,C++语言不允许这样做.相反,你必须这样做:

int *arr = new int[num]; 
Run Code Online (Sandbox Code Playgroud)

创建你的数组.以后你必须[1]使用:

delete [] arr; 
Run Code Online (Sandbox Code Playgroud)

释放记忆.

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

当您稍后调用delete时,相同的内存将返回到它来自的"池"或"堆"内存.

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

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

 std::vector<int> arr;
Run Code Online (Sandbox Code Playgroud)

将作为整数的变量存储工作,你永远不必担心释放内存,甚至在将它们存储在那里之前知道你需要多少.

 std::shared_ptr<int> arr = new int[num]; 
Run Code Online (Sandbox Code Playgroud)

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

[1]如果你不想泄漏内存,那么泄漏内存的"坏风格".如果你这样做,不会让任何人高兴.


She*_*ohn 5

我看过很多关于 C++ 内存分配的帖子,关于“new operator”与“operator new”的问题,关于new int(100)vs 的new int[100]问题,关于内存初始化的问题......我认为应该有一个答案,一劳永逸地总结一切,我选择这个问题来写这篇总结。它是关于动态内存分配的,运行时在堆上的分配。我还提供了一个摘要实现(公共领域)。


C 与 C++

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

  • 在 C (header <cstdlib>) 中,我们主要有mallocandcallocfree。我不谈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 )

请查看这篇文章以进行简洁的比较。


传统 C 动态分配

要点:完整的类型擦除(void*指针),因此没有构造/销毁,以字节为单位指定的大小(通常使用sizeof)。

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

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


C++ 动态分配

要点:由于相似的语法做不同的事情而造成混淆,所有 - delete语句调用析构函数,所有 - delete语句采用完全类型的指针,一些 - new语句返回完全类型的指针,一些 - new语句调用某些构造函数。

警告:正如您将在下面看到的,new可以是关键字函数。最好不要谈论“new operator”和/或“operator new”以避免混淆。我将new任何包含new函数或关键字的有效语句称为“-statements”。人们还谈论“new-expressions”,其中new是关键字而不是函数。

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

不要自己使用这个。这由new 表达式内部使用(见下文)。

这些分配不会初始化内存,特别是,它们不会在分配的对象上调用默认构造函数。因此,您必须在使用delete或释放分配之前手动初始化所​​有元素delete[]

注意:我再怎么强调你也不应该自己使用它。如果你要使用它,但要确保你传递一个指针void调用既可以当的,而不是一个类型的指针deletedelete[]对这种分配(随时手动初始化之后)。我个人在使用某些编译器时遇到过非 POD 类型的运行时错误(可能是我的错误)。

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

不要自己使用这个。这由new 表达式内部使用(见下文)。在下文中,我假设void *ptr = ::operator new( n*sizeof(T) )某些类型T和大小n

然后从使用默认构造函数开始::operator new( n*sizeof(T), (T*) ptr )初始化n类型元素。这里没有分配,只有使用默认构造函数初始化。TptrT::T()

单对象分配和初始化

  • new T( args )使用构造函数为单个类型的对象分配初始化内存。除非省略参数(即甚至),否则不会调用默认构造函数。失败时抛出异常。TT::T( args )new T()new Tstd::bad_alloc
  • new (std::nothrow) T( args )除了它NULL在失败的情况下返回之外相同。
  • 使用delete调用析构函数T::~T()和释放相应的内存。

多对象分配和初始化

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

内存初始化(又名“placement new”)

这里没有分配。无论分配是如何进行的:

  • new (ptr) T(args)调用T::T(args)存储在 的内存上的构造函数ptr。除非省略参数,否则不会调用默认构造函数。
  • new (ptr) T[n]调用默认构造T::T()n类型的对象T,从存储ptrptr+n(即,n*sizeof(T)字节)。

相关文章