在C++中有没有一种方法可以扩展动态内存数组?

3
有没有一种方法可以扩展动态内存数组?就像这样:
int *a = new int[5];
*a = new int[2];

这合法吗?


4
当然,那段代码是合法的,但它可能并不会按照你的期望运作。 - Bwmat
9
请使用std::vector<int> - GManNickG
5
实际上,这是不合法的,从int *int没有隐式转换。 - Matteo Italia
1
通常情况下,您需要将现有内容复制到一个临时变量中,然后创建一个具有新扩展大小的数组,然后使用临时变量的值初始化新数组。最后,您删除您的临时变量。例如,这就是std::vector在内部工作的方式。 - FailedDev
1
我同意 @GMan 的观点,std::vector<T> 提供了自动调整大小的功能,您无需担心。与 C 语言中的 realloc() 函数不同,C++ 中没有标准构造函数可重新分配使用 new 分配的内存,因此通常情况下需要使用 new 分配更多内存,将旧数据块中的数据复制到新块中,然后释放旧指针使用 delete - wkl
显示剩余2条评论
2个回答

10

你无法扩展这种类型的动态内存数组。但如果你需要这个功能,可以使用mallocrealloc,但我建议不要这样做,而是建议包含<vector>并使用std::vector。它有一个resize方法。

另外,你描述的代码将无法编译。以下代码可以编译:

1: int *a = new int[5];
2: a = new int[2];
上述代码将分配两个内存块,但都不会被销毁。第二行仅仅是将一个新的数组赋给了同一个 int *a 指针。当一个已分配的内存不再被任何指针引用时,就称为内存泄漏。上述代码丢失了对 new int[5] 的所有引用,并且没有办法将此内存释放回操作系统。
虽然这不是很实际的例子,但有多种方法可以调整数组/向量的大小。由于通常需要增加数组大小,因此我会这样做:
{ // C++ vector on the stack (although internally vector uses memory from the heap)
    std::vector<int> a(1024);
    // do smth
    a.resize(4096); // note: this does not always reallocate
    // do smth else
}

{ // C++ everything on the heap
    std::vector<int> *a = new std::vector<int>(1024);
    // do smth
    a->resize(4096); // note: this does not always reallocate
    // do smth else
    delete a;
}

{ // C style
    int *a = (int*)malloc(1024*sizeof(int));
    // do smth
    a = realloc(a, 4096*sizeof(int));
    // do smth else
    free(a);
}

值得注意的是,realloc并没有进行任何智能处理。 它所做的只是:

  • 分配新的内存块malloc
  • 将数据从旧的内存块复制到新的内存块memcpy
  • 释放旧的内存块free
  • 返回新的内存块

1
值得指出的是,std::vector 将使用复制/移动运算符,而任何 C 风格的版本对于非 POD 类型会产生未定义行为。 - spraff
2
"// C++ everything on the heap" 这个部分的目的是什么? - GManNickG
只是实现同一目的的不同方式。也许在后面跟着“delete”就没有太多意义了,但通常情况下,您有时会使用“new”来创建向量,您同意吗? - RushPL
2
@RushPL:不经常,我想不出有过这样的时候。 - GManNickG
C++11 最近才添加了适当传递底层分配指针的方法 - 请参见 http://en.wikipedia.org/wiki/C%2B%2B11#Rvalue_references_and_move_constructors 在 C++98 中,通过值传递这样的对象通常会不必要地复制内存。 - RushPL
C语言风格有一个bug -- malloc需要使用free释放内存,而不是delete - Robᵩ

1

你可以扩展一个数组,但是你需要注意复制内容和释放旧数组(顺便说一下,你的代码除了语法错误外还缩小了数组)。

这正是 std::vector 的工作方式,只不过你不需要关心。

所以基本上,已经分配了 int *a,需要发生的事情就像这样:

{
    std::unique_ptr<int[]> d(a);
    a = new int[desired_new_size];
    for(unsigned int i = 0; i < min_old_size_and_new_size; ++i)
        a[i] = d[i];
}

请注意,严格来说,“扩展”数组从未真正扩展过,而是用另一个更大的数组替换它(对于提供相同功能的任何容器也是如此)。但是,对于稍后使用指针的任何代码来说,这是透明的,没有人会知道。
如上所述,您不应将realloc(或任何其他C内存分配函数)与由operator new和delete(或new[]和delete[])分配或释放的内存组合使用。
这可能有效(通常会),但在概念上是错误的,如果不崩溃,则纯粹是运气(未知的实现细节)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接