【问题标题】:Dynamic allocation in java or c++ [closed]java或c ++中的动态分配[关闭]
【发布时间】:2013-06-23 17:10:09
【问题描述】:

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

array=new int[10];

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

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

【问题讨论】:

  • 你是对的。它将被 Java 中的零数组替换。
  • 不,它将被随机值数组替换(实际上是之前在内存中的值)。 C++ 不初始化数组内容!
  • 我认为这个问题太模糊了——不同语言的几个问题......
  • 有趣的是,大多数答案似乎都忽略了问题的后半部分,这才是真正有趣的部分......
  • 注意,realloc 不一定只是调整旧内存块的大小。如果数组之后没有足够的可用空间来执行此操作,它将分配一个新数组并复制旧值。这就是为什么它会给你一个指针;指针可能指向与您传入的位置完全不同的位置。

标签: java c++ memory dynamic allocation


【解决方案1】:

每当您执行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 时,您只会丢失对第一个数组的引用。由于它是一个 new 数组,它将遵守语言的新分配数组规则:在 Java 中,数组现在将指向一个大小为 15 且填充了零的数组;在 C++ 中,array 将指向一个大小为 15 且填充了垃圾的数组。

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

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

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

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

【讨论】:

  • 迄今为止的最佳答案 :) 您能否详细介绍最后一部分,使用 realloc 吗?为什么它在 C 而不是 C++ 中工作(对于原始类型,我的意思是)
  • 怎么回事,“它在 C++ 中不起作用”?
  • @Radu realloc 在 C 和 C++ 中的工作方式相同。
  • 是的,对不起,我看错了你的答案。好吧,如果我使用 realloc 重新分配更多内存,比如说 sizeof(int) 更多内存,我认为如果那个地方没有重新分配的空间,它只会复制数组。否则,它只会要求更大的内存块,从而扩展数组?
  • @Radu,我不确定确切的行为。我认为如果有空间它确实可能只是扩展块,但是你怎么知道运行时是否认为有足够的空间?根据用例,您需要检查新分配的内存块是否在同一位置(如果地址已更改,则更新旧指针),或者如果您只是有一个要替换的指针,您根本不关心它——如果地址改变或保持不变,你的代码将是一样的。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    最初的前 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]();
    //                    ^^
    

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        【解决方案5】:

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

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

        【讨论】:

        • 这就是我想知道的,是否可以动态扩展数组。 Vector 在内部是如何工作的?
        • 使用 ArrayList 而不是 Vector,除非您需要它是线程安全的。它里面有一个数组。当你填满所有空间并需要添加一个 mroe 时,它​​会将所有内容复制到一个更大的数组并释放对前一个数组的引用(以便它被垃圾收集)
        【解决方案6】:

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

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

        Api Docs

        array = Arrays.copyOf(array, 15);
        

        【讨论】:

        • 每次都不复制数组 ...
        • @jlordo 我认为 OP 意味着无需 手动 每次都复制数组 ...
        • 这是错误的。数组不会被扩展,你只会得到一个新分配的数组。对旧数组的任何引用仍将指向具有旧大小的旧数组。
        • @BrunoReis 好论证……没想到数组是共享的……
        • 那么如果原始数组的大小为 10 并且我执行 array=Arrays.copyOf(array, 20),我会得到一个前 10 个字段与原始数组相似的新数组吗?
        【解决方案7】:

        在 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 我们要求它。但我们不能使用它,因为我们不知道它在哪里。


        现在有一些有用的东西。使用向量,向量是 C++ 中内置动态内存分配的对象,因此您不必自己手动进行。

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

        【讨论】:

          【解决方案8】:

          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。

          【讨论】:

          • 大部分是题外话。首先,它不是 STL,而是标准库,尽管事实上大多数人会混淆它们,但它们是不同的。其次,我要求的是完全不同的东西。你知道“不使用向量,不复制数组”是什么意思吗?第三,你从哪里得到我是初学者的想法?第四,不,它根本没有帮助。当人们回答没有被问到的问题时,我非常恼火。
          • 关于你是初学者的想法是因为你想自己制作一些东西,而不是使用像矢量这样的可信来源。
          【解决方案9】:

          是的,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 的等价物,不,没有renew 对应于new 的方式有一个realloc 对应于malloc。这不是语言中缺少的东西。它已通过std::vector 类解决。它自己管理它的内存,它是高效的,不,使用它并不是不纯的风格。拥有一个可以调整大小的数组是 C++ 中的标准方式。

          【讨论】:

            猜你喜欢
            • 2014-09-01
            • 1970-01-01
            • 2016-10-04
            • 2020-11-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-03-12
            相关资源
            最近更新 更多