Java 或 C++ 中的动态分配

Dynamic allocation in java or c++

本文关键字:动态分配 C++ Java      更新时间:2023-10-16

如果我在C++中有一个指针,假设int* array;,我为数组分配内存

array=new int[10];

然后,我初始化数组的所有 10 个元素,使用 0,1,2,3...在那之后,我做array=new int[15];最初的前 10 个值还会存在吗?我想不是,如果我错了,请纠正我。

在C语言中,有函数realloc,它具有上述效果。C++或java中是否有等价物?如何在 C++ 或 Java 中动态扩展数组(不使用 Vector 类,并且每次都不在另一个容量翻倍的数组中复制数组(?

每当new int[X] X 是整数时,无论是在 C++ 还是 Java 中,您都会获得对新分配数组的引用。

在 Java 中,数组会自动初始化,以便每个条目都有其默认值(0 表示基元数据类型,null 表示引用数据类型(。在C++中,数组没有初始化,你会得到垃圾。

如果您这样做:

array = new int[10];
array[0] = 0;
array[1] = 1;
// etc
array = new int[15];

第二次创建数组并在变量array中放置对它的引用时,您只会丢失对第一个数组的引用。由于它是一个数组,它将遵守新分配数组的语言规则:在 Java 中,数组现在将指向大小为 15 的数组,填充零;在C++中,数组将指向大小为 15 的充满垃圾的数组。

在 Java 中,丢失的数组最终将为您进行垃圾回收。在C++中,您刚刚创建了内存泄漏。

这两种语言都禁止您调整大小,或者像您所说的那样动态扩展数组。您可以创建一个新文件,将所有内容从旧文件复制到新文件,然后丢弃旧文件。他们可能会提供为您执行这些操作的方法,但您不会扩展现有数组,您只需创建一个新数组并将数据从旧数组复制到新数组。

在 Java 中没有 realloc(但它有 Arrays.copyOf,其工作原理类似(,而在 C++(和 C(中,realloc不会真正扩展数组;它将在其他地方分配更多内存,释放先前分配的内存,并返回新指针:您必须替换任何指向新地址的现有指针!

最后,对于动态调整自身大小的集合类,它们通常有一个内部数组,每当该数组已满时,该类都会在内部执行所有调整大小的操作:它分配一个新的,更大的,复制元素,然后丢弃旧的。由于数组完全封装在类中,因此您无需担心对旧数组的引用,如我上面所解释的那样。

在java中,内存管理由JVM控制。这就是爪哇的美妙之处。您可以使用 System.arraycopy(( 函数来制作数组的副本。如果您的目标是扩展阵列,只需提供一个更大的数组作为目标数组。

另一方面,您可以使用集合框架来动态扩展集合。

数组概念的核心,无论是在C++还是Java中,都是固定大小的集合。 在这个概念中,realloc可能看起来像某种后门,但它仍然不承诺扩展给定的数组 - 它可以在其他位置创建数组,复制原始内容并释放原始内存。而且很可能会。
因此,如果您想要可变大小集合,请在 C++ 中使用 std::vector,在 Java 中使用ArrayList。或者,您可以自己编写此功能。但是恐怕您将不得不从自己的内存分配器开始,因为一旦分配了内存块,您就无法使标准内存分配器扩展。

最初的前 10 个值还会存在吗?

在C++中,会有某个地方,但你已经失去了对它们的控制。它们将无法访问。这会导致内存泄漏。

int* array=new int[10]; // array points to dynamically allocated array
array=new int[15]; // array points to a completely different place now

在上面的示例中,array指针是第一个动态分配的数组上的唯一句柄。通过将其指向其他地方,您将泄漏阵列。

另请注意,在C++数组的元素不是零初始化的。为此,您需要对数组进行值初始化:

int* array=new int[10]();
//                    ^^

在 Java 中,您无法动态扩展数组。有不同的数据结构,如ArrayList。

在 Java 中,在您的示例中,如果没有对大小为 10 的第一个数组的引用,则它将被 GarbageCollector 收集。

如何在 Java 中动态扩展数组(不使用 Vector 类,并且每次都不在另一个容量翻倍的数组中复制数组(?

java.util.Arrays,有很多方法可以使用。在您的情况下,您需要copyOf

接口文档

array = Arrays.copyOf(array, 15);

在C++ new 总是返回一个指针。数组的名称是指向数组中第一个元素的指针,因此这是将要发生的事情。

 int *array;           //get a point of type int
 array=new int[10];    //allocate 10 ints, and set the array ponter to the first one
 array = new int[15]   //allocate 15 ints, and set the array pointer to the first one

问题是现在我们无法知道前 10 个整数在内存中的位置。操作系统"认为"我们正在使用它 b/c 我们要求它。但是我们不能使用它b/c,我们不知道它在哪里。


现在做一些有用的事情。使用向量,向量是 c++ 中内置动态内存分配的对象,因此您不必自己手动操作。

如果你真的想看看它是如何完成的,你可以自己做处理内存分配的对象。

C++中最好的选择是 stl 和std::vector<int>我不知道为什么你不能使用它,但让我们说,你不能。可能是最好的方法:

const int c_startSize = 10;
const int c_increasing = 13;   //1.3
int * array;
int arraySize = c_startSize;
array = new int[arraySize];
//some code
//now we need to increase size of array.
int * tmp;
tmp = new int[arraySize * c_increasing / 10];
for (int i = 0; i < arraySize; i++)
    tmp[i] = array[i];
arraySize = arraySize * c_increasing / 10;
delete [] array;
array = tmp;
//some code

这可能是唯一的方法。当然,您可以使用reallocmemcpy来复制值,但它基于空指针,对于初学者来说通常更棘手。希望这有所帮助,不要忘记为这个东西创建一个类或结构,否则,它会变得一团糟。

编辑:忘了提了,我的回答只包括C++,没有JAVA。

是的,C++中有一个等价物,即标准C++。

std::vector<int> array(10);

然后

array.resize(15);

vector完全按照您期望的方式管理其存储内存。该vector旨在替换 C 重新分配的数组指针。要替换堆栈上的数组,您std::array自 C++11 起。要替换堆栈上的 VLA,您将在 C++14 或 C++17 中std::dynarray

不要被引诱,realloc偶尔会复制其数据。(当它找不到足够的空间来获取重新分配的缓冲区时(

大约相当于C++的realloc,不,没有对应于new renew的方式,就像有一个对应于mallocrealloc一样。而且它不是语言中缺少的东西。它已在std::vector类中得到解决。它自己管理它的内存,它是高效的,不,使用它并不是不纯粹的风格。这是C++拥有可以调整大小的数组的标准方法。