用new重新分配内存是否安全

Is it safe to realloc memory allocated with new?

本文关键字:内存 是否 安全 分配 new 新分配      更新时间:2023-10-16

根据这里的内容,new自由存储中分配,而malloc使用,这两个术语通常意味着相同的含义。

根据这里所写的内容,realloc可以将存储器块移动到新的位置。如果空闲存储和堆是两个不同的内存空间,那么这意味着有什么问题吗?

具体来说,我想知道使用是否安全

int* data = new int[3];
// ...
int* mydata = (int*)realloc(data,6*sizeof(int));

如果没有,是否有其他方法可以安全地使用new分配realloc内存?我可以分配新的区域和memcpy的内容,但据我所知,如果可能的话,realloc可能会使用相同的区域。

您只能通过malloc(或系列,如calloc)分配的realloc

这是因为跟踪可用和已用内存区域的底层数据结构可能截然不同。

这很可能是,但决不能保证C++new和C malloc使用相同的底层分配器,在这种情况下,realloc可以同时适用于两者。但从形式上讲,那是在乌兰巴托。在实践中,这只是不必要的风险。


C++不提供与CCD_ 14相对应的功能。

最接近的是像std::vector这样的容器(的内部缓冲区)的自动重新分配。

C++容器的设计方式排除了CCD_ 16的使用。


代替呈现的代码

int* data = new int[3];
//...
int* mydata = (int*)realloc(data,6*sizeof(int));

…这样做:

vector<int> data( 3 );
//...
data.resize( 6 );

然而,如果你绝对需要realloc的一般效率,并且你必须接受new作为原始分配,那么你唯一的效率途径就是使用编译器特定的方法,知道realloc使用这个编译器是安全的。

否则,如果您绝对需要realloc的一般效率,但不被迫接受new,那么您可以使用mallocrealloc。使用智能指针可以获得与C++容器相同的安全性。

C++对realloc添加的唯一可能相关的限制是,C++的malloc/calloc/realloc不得根据::operator new实现,其free不得根据::operator delete实现(根据C++14[C.malloc]p3-4)。

这意味着您正在寻找的保证在C++中不存在。但是,这也意味着您可以根据malloc来实现::operator new。如果你这样做,那么理论上,::operator new的结果可以传递给realloc

在实践中,您应该关注new的结果与::operator new的结果不匹配的可能性。C++编译器可以例如组合多个CCD_ 37表达式以使用单个CCD_。这是编译器在标准不允许的时候已经做过的事情,IIRC,现在标准允许了(根据C++14[expr.new]p10)。这意味着即使你走这条路,你仍然不能保证将new指针传递给realloc会有任何意义,即使它不再是未定义的行为。

一般情况下,不要这样做。如果您使用带有非平凡初始化的用户定义类型,则在重新分配副本释放的情况下,realloc不会调用对象的析构函数。复制时,复制构造函数也不会被调用。由于不正确使用对象生存期,这可能导致未定义的行为(请参见C++标准§3.8对象生存期,[basic.life])。

1对象的生存期是该对象的运行时属性。如果一个对象是类或聚合类型,并且它或它的一个成员是由非平凡默认构造函数初始化的,则称其具有非平凡初始化。[注意:由琐碎的复制/移动构造函数初始化是非琐碎的初始化。--结束注释]

T型物体的寿命开始于:

--获得了具有适当排列和尺寸的T型存储器,并且

--如果对象进行了非平凡的初始化,那么它的初始化就完成了。

T类型对象的寿命在以下情况下结束:

--如果T是具有非平凡析构函数(12.4)的类类型,则析构函数调用启动,或者

--对象占用的存储器被重新使用或释放。

后来(重点是我的):

3本国际标准中赋予物体的特性仅适用于给定物体的使用寿命

因此,您真的不想在对象生命周期结束后使用它。

它不安全,也不优雅。

可以覆盖new/delete以支持重新分配,但您也可以考虑使用容器。

一般来说,没有

有很多东西必须保持安全:

  1. 逐位复制类型并放弃源必须是安全的
  2. 析构函数必须是琐碎的,或者必须对要解除分配的元素进行原位析构函数
  3. 构造函数要么是琐碎的,要么必须就地构造新元素

琐碎的类型满足上述要求。

此外:

  1. new[]-函数必须在没有任何更改的情况下将请求传递给malloc,也不能在一旁进行任何记账。您可以通过替换全局new[]和delete[],或者替换相应类中的全局new[]或delete[]来强制执行此操作
  2. 编译器不能为了保存分配的元素数量或其他任何东西而要求更多的内存
    没有办法强制这样做,尽管如果类型有一个微不足道的析构函数,编译器不应该保存这样的信息,这是实现质量的问题

是-如果new实际上首先调用了malloc(例如,VC++new就是这样工作的)。

否则不会。请注意,一旦您决定重新分配内存(因为new称为malloc),您的代码是特定于编译器的,不再可在编译器之间移植。

(我知道这个答案可能会让很多开发人员感到不安,但我的答案取决于真实的事实,而不仅仅是惯用的)。

这是不安全的。首先,您传递给realloc的指针必须是从mallocrealloc获得的:http://en.cppreference.com/w/cpp/memory/c/realloc.

其次,new int [3]的结果不必与分配函数的结果相同——可以分配额外的空间来存储元素的计数。

(对于比int更复杂的类型,realloc是不安全的,因为它不调用复制或移动构造函数。)

您可能可以(并非在所有情况下),但不应该。如果需要调整数据表的大小,则应使用std::vector

关于如何使用它的详细信息在另一个SO问题中列出。

这些函数主要用于C.

memset将内存块中的字节设置为特定值。

malloc分配一块内存。

胼胝体,与malloc相同。唯一的区别是它将字节初始化为零。

在C++中,分配内存的首选方法是使用new。

C: int intArray=(int*)malloc(10*sizeof(int));C++:int intArray=new int[10];

C: int intArray=(int*)calloc(10*sizeof(int));C++:int intArray=new int10;