重新分配用 new 分配的内存是否安全?
Is it safe to realloc memory allocated with new?
根据所写 here,new
在 自由存储 中分配,而 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
,那么你可以使用malloc
和realloc
。使用智能指针可以让您获得与 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
的指针必须是从 malloc
或 realloc
获得的: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;
一般不会。
有许多东西必须保持以确保安全:
- 按位复制类型并放弃源必须是安全的。
- 析构函数必须是微不足道的,或者您必须就地析构要释放的元素。
- 要么构造函数不重要,要么您必须就地构造新元素。
普通类型满足上述要求。
另外:
new[]
函数必须将请求传递给 malloc
,不做任何更改,也不做任何簿记。您可以通过替换全局 new[] 和 delete[] 或相应 类. 中的那些来强制执行此操作
- 编译器不得要求更多内存以保存分配的元素数或其他任何内容。
没有办法强制这样做,尽管如果类型有一个微不足道的析构函数,编译器不应该保存这样的信息作为 实现质量. 的问题
根据所写 here,new
在 自由存储 中分配,而 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
,那么你可以使用malloc
和realloc
。使用智能指针可以让您获得与 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
的指针必须是从 malloc
或 realloc
获得的: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;
一般不会。
有许多东西必须保持以确保安全:
- 按位复制类型并放弃源必须是安全的。
- 析构函数必须是微不足道的,或者您必须就地析构要释放的元素。
- 要么构造函数不重要,要么您必须就地构造新元素。
普通类型满足上述要求。
另外:
new[]
函数必须将请求传递给malloc
,不做任何更改,也不做任何簿记。您可以通过替换全局 new[] 和 delete[] 或相应 类. 中的那些来强制执行此操作
- 编译器不得要求更多内存以保存分配的元素数或其他任何内容。
没有办法强制这样做,尽管如果类型有一个微不足道的析构函数,编译器不应该保存这样的信息作为 实现质量. 的问题