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

Is it safe to realloc memory allocated with new?

根据所写 herenew 自由存储 中分配,而 malloc 使用 并且这两个术语通常表示相同的意思。

根据here的记载,realloc可能会将内存块移动到新位置。如果free store和heap是两个不同的内存空间,那说明有什么问题吗?

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

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

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

您只能realloc通过malloc(或家庭,如calloc)分配的资源。

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

可能,但绝不保证 C++ new 和 C malloc 使用相同的底层分配器,在这种情况下 realloc可以为两者工作。但正式地说,这是在 UB 土地上。在实践中,这只是不必要的冒险。


C++ 不提供对应于 realloc 的功能。

最接近的是容器(的内部缓冲区)的自动重新分配,如 std::vector

C++ 容器的设计方式排除了使用 realloc


而不是提供的代码

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++ 容器相同的安全性。

不安全,也不优雅

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

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

没有别的。请注意,一旦您决定重新分配内存(因为 new 调用了 malloc),您的代码是特定于编译器的,并且不再可在编译器之间移植。

(我知道这个答案可能会让很多开发者不高兴,但我的回答是基于真实的事实,而不仅仅是惯用语)。

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

1 The lifetime of an object is a runtime property of the object. An object is said to have non-trivial initialization if it is of a class or aggregate type and it or one of its members is initialized by a constructor other than a trivial default constructor. [ Note: initialization by a trivial copy/move constructor is non-trivial initialization. —end note ]

The lifetime of an object of type T begins when:

— storage with the proper alignment and size for type T is obtained, and

— if the object has non-trivial initialization, its initialization is complete.

The lifetime of an object of type T ends when:

— if T is a class type with a non-trivial destructor (12.4), the destructor call starts, or

— the storage which the object occupies is reused or released.

后来(强调我的):

3 The properties ascribed to objects throughout this International Standard apply for a given object only during its lifetime.

所以,您真的不想使用对象 超出其生命周期

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

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

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

您也许可以(并非在所有情况下),但您不应该这样做。如果您需要调整数据大小 table,则应改用 std::vector

关于如何使用它的详细信息列在另一个 SO question

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++ 编译器可能例如组合多个 new 表达式以使用一个 ::operator new 调用。这是编译器在标准不允许时已经做的事情,IIRC,标准现在允许它(根据 C++14 [expr.new]p10)。这意味着即使你走这条路,你仍然不能保证将你的 new 指针传递给 realloc 会做任何有意义的事情,即使它不再是未定义的行为。

这些函数主要用在C语言中

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

malloc 分配一块内存。

calloc,同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;

一般不会。

有许多东西必须保持以确保安全:

  1. 按位复制类型并放弃源必须是安全的。
  2. 析构函数必须是微不足道的,或者您必须就地析构要释放的元素。
  3. 要么构造函数不重要,要么您必须就地构造新元素。

普通类型满足上述要求。

另外:

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