C ++ - 为数组分配内存的安全性,然后返回一个外部删除的指针

时间:2015-02-21 01:49:48

标签: c++ memory-management

我正在学习C ++,而且还有一些我不清楚的事情。

如果我创建一个为某个类型的数组分配内存然后返回新创建的指针的函数,假定指针只是一个内存地址,相应的delete语句将清除所有的正确分配内存,或者只释放第一个元素,与数组的其余部分一起造成内存泄漏?如果 正确清理了,那么假设返回类型中固有的上下文丢失,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?
}

通常情况下,我会编写一些测试代码来找出答案,但鉴于访问未分配的内存会导致未定义的行为,我不确定我要测试的是什么。

5 个答案:

答案 0 :(得分:3)

must使用delete[] p另一个导致未定义的行为。通常,编译器会在数组之前存储一些数字,以了解它的大小。取决于实施。 main也应该返回int,但这并不严重。

编辑:既然你对可能的实现感兴趣,那就是dissasembly(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)*常量)+ 17个辅助字节存储在数组之前的一个字(8个字节)中。

答案 1 :(得分:1)

每当使用' new'在堆上动态分配数组时(例如int [],bool []等)你想使用delete []删除内存,否则正如Miroslav的回答所指出的那样,你只需使用' delete&#即可获得未定义的行为39;运营商的形式。

如果您使用的是C ++ 11或更高版本,我邀请您查看语言的新智能指针功能,例如std :: unique_ptr,它处理为您释放内存(实际上是RAII)。

答案 2 :(得分:1)

删除p;这是错误的,因为您分配了一个带有new运算符的数组.->第一
删除[] p;这是正确的。 - >第二次

运行C ++程序时,有两种类型的内存,一种是堆栈内存,另一种是堆内存。当你使用operator new系统在内存堆中分配内存时,这个内存分配保持在执行过程的上下文中,因此它被称为动态分配的内存。上下文信息不是保持功能而是保持流程,因为它是一种资源。因此,即使从函数返回后,进程也知道其资源,因此通过使用delete []操作符系统可以清理已分配的内存。数组的第一个指针可能会偏移,数组大小取决于实现,并且在数组的情况下将在删除内存时播放。

答案 3 :(得分:1)

使用new在堆上创建数组时,将返回指向数组中第一个元素的指针。因此,在您的示例中,当您编写delete p时,您要说删除数组中的第一个元素。但是,当你说删除[] p时,你就是说删除整个事情。

答案 4 :(得分:1)

如果它被正确清理,C ++如何知道要解除分配的内容

How does delete[] "know" the size of the operand array?

  

当您在堆上分配内存时,您的分配器将保持跟踪   你分配了多少内存。这通常存储在一个   "头"在您分配的内存之前的段。那样   当它释放内存的时候,解除分配器确切地知道如何   很多记忆要自由。