我在网上找到了这段代码http://www.cplusplus.com/forum/beginner/6644/#msg30551它应该从 c++ 函数返回一个数组。我想要一个解释说明这个函数如何在内存分配、堆栈、堆、指针等方面运行。
int *f(size_t s){
int *ret=new int[s];
for (size_t a=0;a<s;a++)
ret[a]=a;
return ret;
}
我在网上找到了这段代码http://www.cplusplus.com/forum/beginner/6644/#msg30551它应该从 c++ 函数返回一个数组。我想要一个解释说明这个函数如何在内存分配、堆栈、堆、指针等方面运行。
int *f(size_t s){
int *ret=new int[s];
for (size_t a=0;a<s;a++)
ret[a]=a;
return ret;
}
我。
int *ret=new int[s];
1.ret
在堆栈上分配内存 - 这是一个int
指针2.在堆上
分配具有大小的连续内存
3.指向已分配内存的第一个元素(来自 2.)s * sizeof(int)
ret
二、
for (size_t a=0;a<s;a++)
ret[a]=a;
a
for
-statement结束后,a
不再可访问(仅在 中可用for
)三、
return ret;
返回指针的副本ret
,它指向在 I. 中创建的数组的第一个元素,在 II 中初始化。
之后return
,ret
被“销毁”。
这个函数的调用者不能忘记释放(释放)这个内存,调用delete[]
.
例如:
int * my_array = f( 6 );
// do sth with my_array
delete[] my_array;
实际上,该函数不返回int
s 数组(即int[N]
)。它返回的是一个指向int
( int *
) 的指针。s
事实证明,这个指针指向类型元素数组的第一个元素int
。
请注意,内存分配有new
:
int *ret = new int[s];
int
因此,所指向的s数组ret
具有动态存储时长。除其他外,这意味着
1) 编译器不会自动调用每个数组元素的析构函数。(在这种情况下,这不是问题,因为元素是类型的,int
但如果元素是具有非平凡析构函数的类类型的元素,则可能是。)
2) 编译器不会自动释放分配的内存。
相比之下,请考虑以下代码:
void g() {
int p[10]; // allocates 10 integer in the stack
// use p ...
}
当g
终止时,编译器将执行上述操作。为此,必须在编译时设置数组的大小(本例中为 10)。如果您在编译时不知道大小,而不是new
原始代码中所需的大小。
对于动态分配的数组,程序员有责任确保在不再需要数组时执行上述两个操作。为此,您必须调用delete[]
:
delete[] p; // where p is a `int*` with the same value as `ret`
实际上,由于可能引发异常,这比看起来要困难得多。例如,考虑这段代码
void foo() {
int* p = f(10); // where f is in the question
// ... use the array pointed by p
a_function_that_might_throw();
delete[] p;
}
如果确实抛出异常,则执行永远不会到达被删除a_function_that_might_throw
的地步。在这种情况下,由(inside )p
分配的内存在程序终止之前不会被释放(它会泄漏)。new
f
int*
为了避免这个问题,最好使用智能指针(例如std::unique_ptr
or )而不是原始指针(例如std::shared_ptr
)。
最后,默认情况下,分配的内存new
是堆内存。但是,您可以更改此行为。
int *ret = new int[s];
这动态地(在堆上)分配一个s
整数数组并将一个指向它的指针(实际上,指向它的第一个元素)存储在ret
.
我相信其余的功能很简单。
所以该函数将一个指针返回给一个动态分配的数组。这并不安全。如果调用者不存储返回值并稍后调用delete[]
它,它将泄漏。
int *ret=new int[s];
此行定义了一个具有自动存储持续时间的int*
调用。它使用new-expression返回的指针进行ret
初始化。这个new 表达式创建一个具有动态存储持续时间的 s 数组,返回一个指向该数组中第一个元素的指针。ret
new int[s]
s
int
所以我们现在有两个对象:一个int*
具有自动存储持续时间的对象和一个int[]
具有动态存储持续时间的对象。
for (size_t a=0;a<s;a++)
这是一个for
声明。for-init-statement定义了一个名为的size_t
对象a
并将其初始化为 0。条件检查是否a
小于s
。最终表达式递增a
。这意味着a
在范围内循环[0, s)
。
ret[a]=a;
这会将 的值分配给 中a
的a
第 th 个元素ret
。那就是ret[0]
会有价值0
,ret[1]
会有价值1
,等等。
该a
对象现在被销毁,因为它具有自动存储持续时间,并且我们已经到达其范围(for
语句)的末尾。
return ret;
这将返回 的值ret
,正如您所记得的那样,它是一个int*
。因此,函数的返回值int*
指向动态分配数组的第一个元素。
该ret
对象现在被销毁,因为它具有自动存储持续时间,并且我们已经到达其范围(f
函数)的末尾。请注意,这只是函数内部的指针。动态分配的数组仍然存在,返回的指针仍然指向它。
稍后,您必须记住delete[]
返回的指针。