C++ - 为数组分配内存的安全性,然后返回要在外部删除的指针
C++ - safety of allocating memory for an array, then returning a pointer to be deleted externally
我现在正在学习C++,有些事情我不清楚。
如果我创建一个为某种类型的数组分配内存的函数,然后 returns 新创建的指针,假设该指针只是一个内存地址,那么相应的 delete
语句正确地清理所有分配的内存,或者只会释放第一个元素,从而导致数组的其余部分发生内存泄漏?如果它 是 正确清理,考虑到我假定的 return 类型固有的上下文丢失,C++ 如何知道要释放什么?
int* AllocateSomething()
{
int *arr = new int[100];
// fill the array with something...
return arr;
}
int main()
{
int* p = AllocateSomething();
delete p; // what will this do?
delete[] p; // how would this know how much memory to delete?
}
通常我只会编写一些测试代码来找出问题的答案,但考虑到访问未分配的内存会导致未定义的行为,我不确定我要测试什么。
您 must
使用 delete[] p
另一个会导致未定义的行为。通常,编译器会在数组前存储一些数字以了解它有多大。取决于实施。也 main 应该 return int,但这不是那么严重。
编辑:因为您对可能的实现感兴趣,所以这里是 dissassembly (gcc 4.8, linux x86_64):
(gdb) l AllocateSomething
1 int* AllocateSomething()
2 {
3 int *arr1 = new int[100];
4 int *arr2 = new int[200];
5 int *arr3 = new int[300];
6 int *arr4 = new int[400];
7 arr1[0] = arr2[0] = arr3[0] = arr4[0] = ~0;
8
9
10
(gdb) x/20 arr1-8
0x601ff0: 0 0 0 0
0x602000: 0 0 417 0
0x602010: -1 0 0 0
0x602020: 0 0 0 0
0x602030: 0 0 0 0
(gdb) x/20 arr2-8
0x602190: 0 0 0 0
0x6021a0: 0 0 817 0
0x6021b0: -1 0 0 0
0x6021c0: 0 0 0 0
0x6021d0: 0 0 0 0
(gdb) x/20 arr3-8
0x6024c0: 0 0 0 0
0x6024d0: 0 0 1217 0
0x6024e0: -1 0 0 0
0x6024f0: 0 0 0 0
0x602500: 0 0 0 0
(gdb) x/20 arr4-8
0x602980: 0 0 0 0
0x602990: 0 0 1617 0
0x6029a0: -1 0 0 0
0x6029b0: 0 0 0 0
0x6029c0: 0 0 0 0
每个阵列的内存转储。 -1 标记数组的开始。我在开始前从第 8 个元素(4 字节整数)开始打印。可以清楚的看到数组的大小(sizeof(int) * 常量)+数组前一个字(8字节)存储的17个辅助字节
每当您使用 'new'(例如 int[]、bool[] 等)在堆上动态分配数组时,您想要使用 delete[] 删除内存,否则如 Miroslav 所指出的回答,您将仅使用运算符的 'delete' 形式得到未定义的行为。
如果您使用的是 C++11 或更高版本,我邀请您查看该语言的新智能指针功能,例如 std::unique_ptr 为您释放内存(本质上是 RAII)。
删除p;这是错误的,因为您使用新运算符分配了一个数组。-> first
删除[] p;这是对的。 -> 第二
当你运行一个C++程序时,有两种类型的内存,一种是栈内存,另一种是堆内存。当您使用 operator new 系统在内存堆中分配内存并且此内存分配保持在执行过程的上下文中,因此它被称为动态分配的内存。上下文信息不是保持功能而是过程明智的,因为它是一种资源。因此,即使在函数 return 之后,进程也知道它手头的资源,因此通过使用 delete[] 操作员系统可以清理分配的内存。数组的第一个指针可能会随数组大小偏移,具体取决于实现,并且在数组的情况下会在删除内存时播放。
当您使用 new 在堆上创建数组时,您将返回指向数组中第一个元素的指针。因此,在您的示例中,当您编写 delete p 时,您是在说删除数组中的第一个元素。然而,当你说 delete [] p 时,你是说删除整个东西。
如果清理正确,C++怎么知道要释放什么
How does delete[] "know" the size of the operand array?
When you allocate memory on the heap, your allocator will keep track
of how much memory you have allocated. This is usually stored in a
"head" segment just before the memory that you get allocated. That way
when it's time to free the memory, the de-allocator knows exactly how
much memory to free.
我现在正在学习C++,有些事情我不清楚。
如果我创建一个为某种类型的数组分配内存的函数,然后 returns 新创建的指针,假设该指针只是一个内存地址,那么相应的 delete
语句正确地清理所有分配的内存,或者只会释放第一个元素,从而导致数组的其余部分发生内存泄漏?如果它 是 正确清理,考虑到我假定的 return 类型固有的上下文丢失,C++ 如何知道要释放什么?
int* AllocateSomething()
{
int *arr = new int[100];
// fill the array with something...
return arr;
}
int main()
{
int* p = AllocateSomething();
delete p; // what will this do?
delete[] p; // how would this know how much memory to delete?
}
通常我只会编写一些测试代码来找出问题的答案,但考虑到访问未分配的内存会导致未定义的行为,我不确定我要测试什么。
您 must
使用 delete[] p
另一个会导致未定义的行为。通常,编译器会在数组前存储一些数字以了解它有多大。取决于实施。也 main 应该 return int,但这不是那么严重。
编辑:因为您对可能的实现感兴趣,所以这里是 dissassembly (gcc 4.8, linux x86_64):
(gdb) l AllocateSomething
1 int* AllocateSomething()
2 {
3 int *arr1 = new int[100];
4 int *arr2 = new int[200];
5 int *arr3 = new int[300];
6 int *arr4 = new int[400];
7 arr1[0] = arr2[0] = arr3[0] = arr4[0] = ~0;
8
9
10
(gdb) x/20 arr1-8
0x601ff0: 0 0 0 0
0x602000: 0 0 417 0
0x602010: -1 0 0 0
0x602020: 0 0 0 0
0x602030: 0 0 0 0
(gdb) x/20 arr2-8
0x602190: 0 0 0 0
0x6021a0: 0 0 817 0
0x6021b0: -1 0 0 0
0x6021c0: 0 0 0 0
0x6021d0: 0 0 0 0
(gdb) x/20 arr3-8
0x6024c0: 0 0 0 0
0x6024d0: 0 0 1217 0
0x6024e0: -1 0 0 0
0x6024f0: 0 0 0 0
0x602500: 0 0 0 0
(gdb) x/20 arr4-8
0x602980: 0 0 0 0
0x602990: 0 0 1617 0
0x6029a0: -1 0 0 0
0x6029b0: 0 0 0 0
0x6029c0: 0 0 0 0
每个阵列的内存转储。 -1 标记数组的开始。我在开始前从第 8 个元素(4 字节整数)开始打印。可以清楚的看到数组的大小(sizeof(int) * 常量)+数组前一个字(8字节)存储的17个辅助字节
每当您使用 'new'(例如 int[]、bool[] 等)在堆上动态分配数组时,您想要使用 delete[] 删除内存,否则如 Miroslav 所指出的回答,您将仅使用运算符的 'delete' 形式得到未定义的行为。
如果您使用的是 C++11 或更高版本,我邀请您查看该语言的新智能指针功能,例如 std::unique_ptr 为您释放内存(本质上是 RAII)。
删除p;这是错误的,因为您使用新运算符分配了一个数组。-> first
删除[] p;这是对的。 -> 第二
当你运行一个C++程序时,有两种类型的内存,一种是栈内存,另一种是堆内存。当您使用 operator new 系统在内存堆中分配内存并且此内存分配保持在执行过程的上下文中,因此它被称为动态分配的内存。上下文信息不是保持功能而是过程明智的,因为它是一种资源。因此,即使在函数 return 之后,进程也知道它手头的资源,因此通过使用 delete[] 操作员系统可以清理分配的内存。数组的第一个指针可能会随数组大小偏移,具体取决于实现,并且在数组的情况下会在删除内存时播放。
当您使用 new 在堆上创建数组时,您将返回指向数组中第一个元素的指针。因此,在您的示例中,当您编写 delete p 时,您是在说删除数组中的第一个元素。然而,当你说 delete [] p 时,你是说删除整个东西。
如果清理正确,C++怎么知道要释放什么
How does delete[] "know" the size of the operand array?
When you allocate memory on the heap, your allocator will keep track of how much memory you have allocated. This is usually stored in a "head" segment just before the memory that you get allocated. That way when it's time to free the memory, the de-allocator knows exactly how much memory to free.