替换 realloc (C --> C++)

Posted

技术标签:

【中文标题】替换 realloc (C --> C++)【英文标题】:Replacing realloc (C --> C++) 【发布时间】:2011-04-21 14:49:44 【问题描述】:

在较早的问题中,我询问了类型转换指针,但被引导到使用 C++ 分配系统而不是 malloc 的更好解决方案。 (我正在将一些 C 代码转换为 C++)

但是,我仍然有类似功能的问题:

我变了:

tmp = malloc(sizeof(char*) * mtmp); --> tmp = new char*[mtmp];

free(tmp) --> delete [] tmp;

但是,我在以下函数中使用 realloc 做什么:

char* space_getRndPlanet (void)

   int i,j;
   char **tmp;
   int ntmp;
   int mtmp;
   char *res;

   ntmp = 0;
   mtmp = CHUNK_SIZE;
   //tmp = malloc(sizeof(char*) * mtmp); <-- replaced with line below
   tmp = new char*[mtmp];
   for (i=0; i<systems_nstack; i++)
      for (j=0; j<systems_stack[i].nplanets; j++) 
         if(systems_stack[i].planets[j]->real == ASSET_REAL) 
            ntmp++;
            if (ntmp > mtmp)  /* need more space */
               mtmp += CHUNK_SIZE;
               tmp = realloc(tmp, sizeof(char*) * mtmp); <--- Realloc
            
            tmp[ntmp-1] = systems_stack[i].planets[j]->name;

我收到以下错误:

error: invalid conversion from 'void*' to 'char**'|

编辑 2:

好的,我得到的共识是我应该放弃我目前的解决方案(我愿意这样做)。

为了确保我理解正确,你们的意思是,我应该只拥有一个包含对象本身的向量,而不是指向对象的指针数组?

【问题讨论】:

好吧,忽略您在上面的代码中错误地使用 realloc() 的事实。这是 C++ 的一个弱点,因为对象具有构造函数/析构函数。这个问题通过使用向量而不是原始数组来解决。 【参考方案1】:

C 允许 void* 隐式转换为任何指针。 C++ 没有,所以如果你使用realloc,你必须将结果转换为适当的类型。

但更重要的是,在new[] 返回的指针上使用realloc 是未定义的行为。而且没有直接的 C++ 风格等同于 realloc

你的选择是,从最少到最惯用的:

坚持malloc/realloc/free 并投射指针。 使用new[] + delete[] 而不是realloc 使用std::vector&lt;std::string&gt; 而不是管理您自己的内存。

【讨论】:

另外,您不应该混合使用 new/delete 和 malloc/calloc/realloc/free 内存分配。 技术上你应该使用delete[]new[]【参考方案2】:

这似乎是一个根据需要增长的不起眼的数组。

停止使用显式内存分配,您几乎肯定不需要它。使用 std::vector 或其他 C++ 标准库的动态容器,它们会根据您的需要自动增长。

看起来您也在使用以 null 结尾的 C 样式字符串。为什么不改用std::string

【讨论】:

我正在转换一些旧的 C 代码,并且边走边学(不太熟悉 C,只熟悉 C++)。所以这可能有效。【参考方案3】:

在 C++ 中,您不应该使用数组(即使是动态分配的)。

这已被替换为 std::vector

在 C 中:

char** tmp = (char**)malloc(sizeof(char*) * size);
free(tmp);

// And a correct version of realloc
char** alt = (char**)realloc(sizeof(char*) * newSize);
if (alt)

    // Note if realloc() fails then it returns NULL
    // But that does not mean the original object is deallocated.
    tmp = alt;

在 C++ 中

std::vector<char*>   tmp(size);

// No need for free (destructor does that).
tmp.resize(newSize);

【讨论】:

【参考方案4】:

http://www.cplusplus.com/forum/general/18311/

(简而言之 - 没有真正的 C++ 等效于 realloc,但也许您最好使用 vector?)

【讨论】:

你能向我解释一下 realloc 到底在做什么吗?此外,通过用向量替换当前解决方案,这是否意味着我使用的是类似数组的设备(即向量),而不是堆栈。即:这是否意味着我应该替换当前的堆栈解决方案? @Biosci3c 你也可以使用堆栈。 C++ 在标准模板库中定义了这两种类型。见cplusplus.com/reference/stl @Biosci3c - realloc 正在创建更大的内存空间来保存tmp 中的内容,因为旧空间已被填满。可调整大小的 C++ 容器会自动为您执行此操作。您可以使用stackvector;它们都支持“类似堆栈”的操作(但vector 也支持随机访问,而stack 不支持)。 另外,在您当前的解决方案中,tmp 不是堆栈,它是一个数组。 Realloc 将尝试调整当前分配的内存块的大小。如果它不能(比如,你试图扩大它并且有另一个块挡住了),它将分配一个新的内存块,复制指针的内容并返回一个指向结构的新指针。 (除非您这样做,否则原始指针不会更改)。鉴于 C++ 中对象的性质(例如深拷贝与浅拷贝),这种逻辑必须由用户处理,因为编译器不知道需要如何复制。【参考方案5】:

Realloc 并不真正关心调用构造函数,因此在 new 之后使用 realloc 似乎是个坏主意。您应该将 vector 作为更好的方法。您可以调整向量的大小。

【讨论】:

【参考方案6】:

不幸的是,C++ 中没有realloc(因为内存可能包含非平凡构造或不可复制的对象)。要么分配新的缓冲区并复制,要么学习使用std::vectorstd::stack,它们会自动为您完成这项工作。

【讨论】:

【参考方案7】:

我认为从手工制作的动态数组切换到向量是一个不错的首选。

至于向量是否应该直接包含对象,或者包含指向实际对象的指针,没有一个明确的答案——这取决于许多因素。

最大的一个因素是这些是否是我所说的“实体”对象——对于那些复制毫无意义的对象。一个典型的例子就是 iostream 或网络连接。通常没有合乎逻辑的方法来复制或分配这样的对象。如果这是您正在处理的那种对象,那么您几乎无法存储指针。

但是,如果您正在处理通常(松散地)定义为“值对象”的内容,则复制和分配就可以了,并且将对象直接存储在向量中就可以了。对于这样的对象,存储指针的主要原因是当向量必须扩展内存以为更多对象腾出空间时,它可以/将复制对象。如果您的对象太大且复制成本太高以至于无法接受,那么您可能希望在向量中存储类似指针的东西以获得廉价的复制和分配。 很有可能是一个原始指针——它可能是某种智能指针对象,提供更多类似值的语义,因此大多数其他代码可以将该对象视为一个简单值,并且其昂贵的操作等细节可以保持隐藏。

【讨论】:

【参考方案8】:

没有与 realloc() 等效的 C++。

最佳用途:

char* new_tmp = new (char*)[mtmp];
for (int n=0;n<min(mtmp,oldSize);n++) new_tmp[n] = tmp[n];
delete [] tmp;  // free up tmp
tmp = new_tmp;

您得到的错误是因为 C++ 对隐式类型转换不太宽容。

【讨论】:

不是最好的用途——realloc 的想法是保留内存内容。 如果你坚持手动分配内存,你应该分配新的内存,然后将内容复制到新分配的内存中。只有在这两个都成功后,你才能删除旧的记忆。

以上是关于替换 realloc (C --> C++)的主要内容,如果未能解决你的问题,请参考以下文章

realloc 调用会引入多少开销?

为啥使用 realloc() 时会出现双重释放或损坏错误?

什么是 realloc() 的 C++ 版本,用于分配新缓冲区并从旧缓冲区复制内容?

如果 Malloc 无法分配 X 字节,我是使用 Realloc 还是再次使用 Malloc? C++

在 C++ 中使用 realloc

C++之内存管理:申请与释放