【问题标题】:realloc throws error after a particular index size in resizing arrayrealloc 在调整数组大小时在特定索引大小后抛出错误
【发布时间】:2020-01-12 22:51:02
【问题描述】:

所以我正在使用 realloc 和重复加倍制作一个调整大小的数组,我的数组工作正常,直到它的大小为 134217728,但只要我推动第 134217729 个元素,即我调用 134217728*2 的调整大小函数,realloc 返回 0。

我认为我的内存已满,但我有 8 Gbs 的 RAM,并且我在 Vs 代码上使用 windows 10 MinGW 32 位编译器,如果我愿意,如何进一步增加我的数组的大小。 这是 Windows 的问题还是做错了什么?

#include<iostream>
#include<string.h>
#include <ctime>
using namespace std;
template<class X>
class ArrayStack{
    X* a =(int*) malloc(1 * sizeof(int));;
    int top=0;
    int length=1;

    void resize(int size){
        cout<<"resizing to "<<size<<endl;
        X* temp=(X*) realloc (a, size * sizeof(X));
        if(temp==0){
            cout<<"No continous memory left for the stack ";
        }
        length=size;
        a=temp;                
    }

public:
    void push(X item){
        if(top==length){
            resize(length*2);
        }
        a[top++]=item;
    }

    X pop(){
        if(top<=length/4){
            resize(length/2);
        }
        return a[--top];
    }

    bool IsEmpty(){
        return top==0;
    }        
};

int main(){
    ArrayStack <int> newStack;
    for(unsigned long long int i=0;i<134217729 ;i++){
        // In case of int the max size of array stack i can make is of length 134217728 using repeated doubling and realloc
        int r  = rand()%1000;
        newStack.push(r);
    }  
    while(!newStack.IsEmpty()){
        newStack.pop();
    }
}

realloc 返回 0。

【问题讨论】:

  • 不要realloc 你有什么newed。 realloc 只能与malloc 系列的其他成员一起使用。 newrealloc 有可比性,主要是因为 stringvector 这样的容器使其无关紧要。如果你要去realloc 全力以赴malloc 并查找placement new
  • 是的,糟糕的juju...不要将new/deleterealloc 混为一谈,谁知道可能会调用(或唤起... ) 您可以简单地创建一个new tmpX [doubled],然后从X 复制到tmpX,然后delete[] X; 并分配X = tmpX; 以模拟realloc
  • 旁注:malloc 家族是从 C 过来的,C 不知道什么是构造函数和析构函数。如果你的 mallocrealloc 分配包含复杂的类,可能会发生非常讨厌的事情。
  • X* a =(int*) malloc(1 * sizeof(int));ints 调整分配大小,但该类是在X 类上模板化的。这最终会在你身上爆发。
  • @ASHUTOSHSINGH realloc 可能会复制数据。它只会在可以并且愿意的情况下扩展分配。

标签: c++ pointers memory-management new-operator realloc


【解决方案1】:

由于这似乎与家庭作业有关,让我们从基础开始,您可以从中汲取灵感并将它们纳入您的重新分配方案。首先,如上所述,不要将new/deletemalloc/calloc/realloc 混用。虽然它们执行相似的分配功能,但它们的实现完全不同。

也就是说,没有什么可以阻止您编写一个简短的重新分配函数(比如reallocNew),它将使用newdelete 来执行重新分配。由于上面讨论了在重新分配时将当前分配的大小加倍,因此您只需要创建一个类型为 T 的新数组,其当前内存是当前内存的两倍。然后从旧数组复制到新数组(使用memcpy),然后delete[] 旧数组将新重新分配的块返回给调用者以分配给原始指针。

reallocNew 函数的一个简短示例,它接受指向原始内存块的指针以及指向当前元素数量的指针(将在函数内更新并通过指针提供给调用者)可以如下:

template<class T>
T *reallocNew (const T *ptr, size_t *nelem)
{
    /* make new allocated array with 2X the number of elements */
    T *tmp = new T[2 * *nelem];

    /* copy old elements to new block of mem */
    std::memcpy (tmp, ptr, *nelem * sizeof *ptr);
    delete[] ptr;       /* delete the old block of memory */
    *nelem *= 2;        /* update the number of element counter */

    return tmp;         /* return pointer to reallocated block of memory */
}

一个使用重新分配函数的简短示例程序,最初从一个分配的块开始以保存2-int,然后在2, 4 &amp; 8 元素处保存reallocNew,以存储添加到数组中的10-int 值。完整的例子可能是:

#include <iostream>
#include <cstring>

template<class T>
T *reallocNew (const T *ptr, size_t *nelem)
{
    /* make new allocated array with 2X the number of elements */
    T *tmp = new T[2 * *nelem];

    /* copy old elements to new block of mem */
    std::memcpy (tmp, ptr, *nelem * sizeof *ptr);
    delete[] ptr;       /* delete the old block of memory */
    *nelem *= 2;        /* update the number of element counter */

    return tmp;         /* return pointer to reallocated block of memory */
}

int main (void) {

    size_t  nelem = 2,                  /* no of elements alloced */
            used = 0;                   /* no. of element counter */
    int *arr = new int[nelem];          /* allocate initial elements */

    for (; used < 10; used++) {             /* loop adding to array */
        if (used == nelem)                  /* is realloc needed? */
            arr = reallocNew (arr, &nelem); /* call reallocNew function */
        arr[used] = used + 1;               /* add value to array */
    }

    for (size_t i = 0; i < used; i++)  /* loop over stored values outputting */
        std::cout << "arr[" << i << "] : " << arr[i] << '\n';

    delete[] arr;   /* don't forget to free what you allocated */
}

注意:重新分配方案与您在任何地方找到的相同。您希望避免每次添加都重新分配,因此您选择一些合理的方案,例如添加一些固定数量的元素,将电流乘以大于 1 的某个分数,或者提供合理权衡的常见方案是将当前分配加倍每次需要重新分配。这允许添加上面的 10 个元素,只需 3 次重新分配(您最多可以添加 16 个元素而无需再次重新分配)。

(虽然内存将在程序退出时被释放,但 delete[] 用于嵌套在代码中的已分配内存将防止内存泄漏)

使用/输出示例

$ ./bin/newdelrealloc
arr[0] : 1
arr[1] : 2
arr[2] : 3
arr[3] : 4
arr[4] : 5
arr[5] : 6
arr[6] : 7
arr[7] : 8
arr[8] : 9
arr[9] : 10

内存使用/错误检查

在您编写的任何动态分配内存的代码中,对于分配的任何内存块,您都有 2 个职责:(1)始终保留指向起始地址的指针内存块,因此 (2) 当不再需要它时可以释放

您必须使用内存错误检查程序来确保您不会尝试访问内存或写入超出/超出分配块的边界,尝试读取或基于未初始化的值进行条件跳转,最后,以确认您释放了已分配的所有内存。

对于 Linux,valgrind 是正常的选择。每个平台都有类似的内存检查器。它们都易于使用,只需通过它运行您的程序即可。

$ valgrind ./bin/newdelrealloc
==32331== Memcheck, a memory error detector
==32331== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==32331== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==32331== Command: ./bin/newdelrealloc
==32331==
arr[0] : 1
arr[1] : 2
arr[2] : 3
arr[3] : 4
arr[4] : 5
arr[5] : 6
arr[6] : 7
arr[7] : 8
arr[8] : 9
arr[9] : 10
==32331==
==32331== HEAP SUMMARY:
==32331==     in use at exit: 0 bytes in 0 blocks
==32331==   total heap usage: 5 allocs, 5 frees, 72,824 bytes allocated
==32331==
==32331== All heap blocks were freed -- no leaks are possible
==32331==
==32331== For counts of detected and suppressed errors, rerun with: -v
==32331== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

始终确认您已释放已分配的所有内存并且没有内存错误。

检查一下,如果您有任何问题,请告诉我。

【讨论】:

    【解决方案2】:

    32 位程序的最大地址空间为 4 GB。根据环境,允许的实际地址空间可能是其中的一半。这还包括程序代码、静态数据、库、堆栈等!

    调整分配大小(总是使用delete/new,也经常使用realloc)需要在删除旧分配之前创建新分配。

    因此,请考虑先前分配和新分配的总字节大小(元素计数乘以元素类型的大小)。它是否接近或超过 2 GB?

    如果是这样,您的应用程序的可用内存即将耗尽。

    两种解决方案:以较小的块处理数据(不容易、不好玩、性能差),或切换到 64 位编译器(这样做)。

    有 64 位版本的 MinGW 可用。

    【讨论】:

      【解决方案3】:

      我只是根据上面的建议将代码更改为此代码,以将 realloc/malloc/calloc 等与新的模板类混合,但它仍然存在该错误。 我仍然在猜测我没有足够的空间,正如上面的人所建议的那样,感谢大家的支持,从 python 和 JS 这样的语言到 C++ 真的很难,而且有一些小事情会导致很多问题并感谢您耐心地解释我在课堂上问这个问题很开心感谢您的时间,如果您有任何其他方法可以缩短使用向量的时间,请提出建议。

      它是一个任务,用于制作类似于向量的东西它们根据请求所需的索引以及哪个子数组将具有该特定索引

      #include<iostream>
      #include<string.h>
      #include <ctime>
      using namespace std;
      template<class X>
      class ArrayStack{
      X* a =new X[1];
      unsigned long long int top=0;
      unsigned long long int length=1;
      void resize(unsigned long long int size){
          X* temp=new X[size];
          length=size;
          for(unsigned long long int i=0;i<size/2;i++){
              temp[i]=a[i];
          }
          delete []a;
          a=temp;                
      }
      public:
      void push(X item){
          if(top==length){
              resize(length*2);
          }
          a[top++]=item;
      }
      X pop(){
          if(top<=length/4){
              resize(length/2);
          }
          return a[--top];
      }
      bool IsEmpty(){
          return top==0;
      }        
      };
      
      int main(){
      ArrayStack <int> newStack;
      for(unsigned long long int i=0;i<134217728 ;i++){
          // In case of int the max size of array stack i can make is of length 134217728 using repeated doubling and realloc
          int r  = rand()%1000;
          newStack.push(r);
      }  
      while(!newStack.IsEmpty()){
          newStack.pop();
      }
      }
      

      【讨论】:

        猜你喜欢
        • 2017-08-24
        • 1970-01-01
        • 1970-01-01
        • 2016-08-24
        • 2019-03-07
        • 2018-01-26
        • 2017-06-15
        • 2012-03-17
        • 1970-01-01
        相关资源
        最近更新 更多